pax_global_header 0000666 0000000 0000000 00000000064 14450471353 0014520 g ustar 00root root 0000000 0000000 52 comment=ea27928591bf753de4a14e4ee0e86e293fcbfd1c
marshmallow-1.1.5/ 0000775 0000000 0000000 00000000000 14450471353 0014052 5 ustar 00root root 0000000 0000000 marshmallow-1.1.5/.github/ 0000775 0000000 0000000 00000000000 14450471353 0015412 5 ustar 00root root 0000000 0000000 marshmallow-1.1.5/.github/workflows/ 0000775 0000000 0000000 00000000000 14450471353 0017447 5 ustar 00root root 0000000 0000000 marshmallow-1.1.5/.github/workflows/codeql.yml 0000664 0000000 0000000 00000004432 14450471353 0021444 0 ustar 00root root 0000000 0000000 # For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '43 19 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
# âī¸ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
marshmallow-1.1.5/.github/workflows/dependency-review.yml 0000664 0000000 0000000 00000001564 14450471353 0023615 0 ustar 00root root 0000000 0000000 # Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Reqest, 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
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v1
marshmallow-1.1.5/.github/workflows/go.yml 0000664 0000000 0000000 00000000545 14450471353 0020603 0 ustar 00root root 0000000 0000000 name: Go
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
marshmallow-1.1.5/.gitignore 0000664 0000000 0000000 00000000041 14450471353 0016035 0 ustar 00root root 0000000 0000000 /.idea
coverage.out
profile.out
marshmallow-1.1.5/CHANGELOG.md 0000664 0000000 0000000 00000004050 14450471353 0015662 0 ustar 00root root 0000000 0000000 # Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [[1.1.5](https://github.com/PerimeterX/marshmallow/compare/v1.1.4...v1.1.5)] - 2023-07-03
### Added
- Support for reporting errors from `HandleJSONData` - [info](https://github.com/PerimeterX/marshmallow/issues/27).
## [[1.1.4](https://github.com/PerimeterX/marshmallow/compare/v1.1.3...v1.1.4)] - 2022-11-10
### Fixed
- Fixed problem with nested object implementing JSONDataHandler with skipPopulateStruct - [info](https://github.com/PerimeterX/marshmallow/issues/18).
- Fixed problem with nested object implementing JSONDataHandler with skipPopulateStruct in ModeFailOverToOriginalValue - [info](https://github.com/PerimeterX/marshmallow/issues/19).
## [[1.1.3](https://github.com/PerimeterX/marshmallow/compare/v1.1.2...v1.1.3)] - 2022-08-31
### Added
- Support for excluding known fields from the result map - [info](https://github.com/PerimeterX/marshmallow/issues/16).
## [[1.1.2](https://github.com/PerimeterX/marshmallow/compare/v1.1.1...v1.1.2)] - 2022-08-23
### Added
- Support capturing nested unknown fields - [info](https://github.com/PerimeterX/marshmallow/issues/15).
## [[1.1.1](https://github.com/PerimeterX/marshmallow/compare/v1.1.0...v1.1.1)] - 2022-08-21
### Fixed
- Fix parsing bug for unknown nested fields - [info](https://github.com/PerimeterX/marshmallow/issues/12).
## [[1.1.0](https://github.com/PerimeterX/marshmallow/compare/v0.0.1...v1.1.0)] - 2022-07-10
### Fixed
- Fixed an issue with embedded fields - [info](https://github.com/PerimeterX/marshmallow/issues/9).
## [[0.0.1](https://github.com/PerimeterX/marshmallow/tree/v0.0.1)] - 2022-04-21
### Added
- All functionality from our internal repository, after it has been stabilized on production for several months - [info](https://www.perimeterx.com/tech-blog/2022/boosting-up-json-performance-of-unstructured-structs-in-go/).
marshmallow-1.1.5/CODE_OF_CONDUCT.md 0000664 0000000 0000000 00000012655 14450471353 0016662 0 ustar 00root root 0000000 0000000
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[opensource-conduct@humansecurity.com](mailto:opensource-conduct@humansecurity.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
marshmallow-1.1.5/CONTRIBUTING.md 0000664 0000000 0000000 00000003312 14450471353 0016302 0 ustar 00root root 0000000 0000000 # How To Contribute
We'd love to accept your patches and contributions to this project. There are just a few guidelines you need to follow which are described in detail below.
## 1. Fork this repo
You should create a fork of this project in your account and work from there. You can create a fork by clicking the fork button in GitHub.
## 2. One feature, one branch
Work for each new feature/issue should occur in its own branch. To create a new branch from the command line:
```shell
git checkout -b my-new-feature
```
where "my-new-feature" describes what you're working on.
## 3. Add unit tests
If your contribution modifies existing or adds new code please add corresponding unit tests for this.
## 4. Ensure that the build passes
Run
```shell
go test -v
```
and check that there are no errors.
## 5. Add documentation for new or updated functionality
Please review the [README.md](README.md) file in this project to see if they are impacted by your change and update them accordingly.
## 6. Add to CHANGELOG.md
Any notable changes should be recorded in the CHANGELOG.md following the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) conventions.
## 7. Submit a pull request and describe the change
Push your changes to your branch and open a pull request against the parent repo on GitHub. The project administrators will review your pull request and respond with feedback.
# How your contribution gets merged
Upon pull request submission, your code will be reviewed by the maintainers. They will confirm at least the following:
- Tests run successfully (unit, coverage, style).
- Contribution policy has been followed.
A (human) reviewer will need to sign off on your pull request before it can be merged.
marshmallow-1.1.5/LICENSE 0000664 0000000 0000000 00000002053 14450471353 0015057 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2022 PerimeterX
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
marshmallow-1.1.5/README.md 0000664 0000000 0000000 00000024064 14450471353 0015337 0 ustar 00root root 0000000 0000000 # Marshmallow

[](https://github.com/PerimeterX/marshmallow/actions/workflows/codeql.yml?query=branch%3Amain++)
[](https://github.com/PerimeterX/marshmallow/actions/workflows/go.yml?query=branch%3Amain)
[](https://github.com/PerimeterX/marshmallow/actions/workflows/dependency-review.yml?query=branch%3Amain)
[](https://goreportcard.com/report/github.com/perimeterx/marshmallow)

[](https://pkg.go.dev/github.com/perimeterx/marshmallow)
[](LICENSE)
[](https://github.com/PerimeterX/marshmallow/releases)

[](https://github.com/PerimeterX/marshmallow/issues)
[](https://github.com/PerimeterX/marshmallow/pulls)
[](https://github.com/PerimeterX/marshmallow/commits/main)
[](CODE_OF_CONDUCT.md)
Marshmallow package provides a simple API to perform flexible and performant JSON unmarshalling in Go.
Marshmallow specializes in dealing with **unstructured struct** - when some fields are known and some aren't,
with zero performance overhead nor extra coding needed.
While unmarshalling, marshmallow allows fully retaining the original data and access
it via a typed struct and a dynamic map.
## Contents
- [Install](#install)
- [Usage](#usage)
- [Performance Benchmark And Alternatives](#performance-benchmark-and-alternatives)
- [When Should I Use Marshmallow](#when-should-i-use-marshmallow)
- [API](#api)
## Install
```sh
go get -u github.com/perimeterx/marshmallow
```
## Usage
```go
package main
import (
"fmt"
"github.com/perimeterx/marshmallow"
)
func main() {
v := struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}{}
result, err := marshmallow.Unmarshal([]byte(`{"foo":"bar","boo":[1,2,3],"goo":12.6}`), &v)
fmt.Printf("v=%+v, result=%+v, err=%v", v, result, err)
// Output: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar goo:12.6], err=
}
```
**Examples can be found [here](example_test.go)**
## Performance Benchmark And Alternatives
Marshmallow performs best when dealing with mixed data - when some fields are known and some are unknown.
More info [below](#when-should-i-use-marshmallow).
Other solutions are available for this kind of use case, each solution is explained and documented in the link below.
The full benchmark test can be found
[here](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go).
|Benchmark|Iterations|Time/Iteration|Bytes Allocated|Allocations|
|--|--|--|--|--|
|[unmarshall twice](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L40)|228693|5164 ns/op|1640 B/op|51 allocs/op|
|[raw map](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L66)|232236|5116 ns/op|2296 B/op|53 allocs/op|
|[go codec](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L121)|388442|3077 ns/op|2512 B/op|37 allocs/op|
|[marshmallow](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L16)|626168|1853 ns/op|608 B/op|18 allocs/op|
|[marshmallow without populating struct](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L162)|678616|1751 ns/op|608 B/op|18 allocs/op|

**Marshmallow provides the best performance (up to X3 faster) while not requiring any extra coding.**
In fact, marshmallow performs as fast as normal `json.Unmarshal` call, however, such a call causes loss of data for all
the fields that did not match the given struct. With marshmallow you never lose any data.
|Benchmark|Iterations|Time/Iteration|Bytes Allocated|Allocations|
|--|--|--|--|--|
|[marshmallow](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L16)|626168|1853 ns/op|608 B/op|18 allocs/op|
|[native library](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L143)|652106|1845 ns/op|304 B/op|11 allocs/op|
|[marshmallow without populating struct](https://github.com/PerimeterX/marshmallow/blob/8c5bba9e6dc0033f4324eca554737089a99f6e5e/benchmark_test.go#L162)|678616|1751 ns/op|608 B/op|18 allocs/op|
## When Should I Use Marshmallow
Marshmallow is best suited for use cases where you are interested in all the input data, but you have predetermined
information only about a subset of it. For instance, if you plan to reference two specific fields from the data, then
iterate all the data and apply some generic logic. How does it look with the native library:
```go
func isAllowedToDrive(data []byte) (bool, error) {
result := make(map[string]interface{})
err := json.Unmarshal(data, &result)
if err != nil {
return false, err
}
age, ok := result["age"]
if !ok {
return false, nil
}
a, ok := age.(float64)
if !ok {
return false, nil
}
if a < 17 {
return false, nil
}
hasDriversLicense, ok := result["has_drivers_license"]
if !ok {
return false, nil
}
h, ok := hasDriversLicense.(bool)
if !ok {
return false, nil
}
if !h {
return false, nil
}
for key := range result {
if strings.Contains(key, "prior_conviction") {
return false, nil
}
}
return true, nil
}
```
And with marshmallow:
```go
func isAllowedToDrive(data []byte) (bool, error) {
v := struct {
Age int `json:"age"`
HasDriversLicense bool `json:"has_drivers_license"`
}{}
result, err := marshmallow.Unmarshal(data, &v)
if err != nil {
return false, err
}
if v.Age < 17 || !v.HasDriversLicense {
return false, nil
}
for key := range result {
if strings.Contains(key, "prior_conviction") {
return false, nil
}
}
return true, nil
}
```
## API
Marshmallow exposes two main API functions -
[Unmarshal](https://github.com/PerimeterX/marshmallow/blob/0e0218ab860be8a4b5f57f5ff239f281c250c5da/unmarshal.go#L27)
and
[UnmarshalFromJSONMap](https://github.com/PerimeterX/marshmallow/blob/0e0218ab860be8a4b5f57f5ff239f281c250c5da/unmarshal_from_json_map.go#L37).
While unmarshalling, marshmallow supports the following optional options:
* Setting the mode for handling invalid data using the [WithMode](https://github.com/PerimeterX/marshmallow/blob/0e0218ab860be8a4b5f57f5ff239f281c250c5da/options.go#L30) function.
* Excluding known fields from the result map using the [WithExcludeKnownFieldsFromMap](https://github.com/PerimeterX/marshmallow/blob/457669ae9973895584f2636eabfc104140d3b700/options.go#L50) function.
* Skipping struct population to boost performance using the [WithSkipPopulateStruct](https://github.com/PerimeterX/marshmallow/blob/0e0218ab860be8a4b5f57f5ff239f281c250c5da/options.go#L41) function.
In order to capture unknown nested fields, structs must implement [JSONDataErrorHandler](https://github.com/PerimeterX/marshmallow/blob/195c994aa6e3e0852601ad9cf65bcddef0dd7479/options.go#L76).
More info [here](https://github.com/PerimeterX/marshmallow/issues/15).
Marshmallow also supports caching of refection information using
[EnableCache](https://github.com/PerimeterX/marshmallow/blob/d3500aa5b0f330942b178b155da933c035dd3906/cache.go#L40)
and
[EnableCustomCache](https://github.com/PerimeterX/marshmallow/blob/d3500aa5b0f330942b178b155da933c035dd3906/cache.go#L35).
## Contact and Contribute
Reporting issues and requesting features may be done in our [GitHub issues page](https://github.com/PerimeterX/marshmallow/issues).
Discussions may be conducted in our [GitHub discussions page](https://github.com/PerimeterX/marshmallow/discussions).
For any further questions or comments you can reach us out at [open-source@humansecurity.com](mailto:open-source@humansecurity.com).
Any type of contribution is warmly welcome and appreciated â¤ī¸
Please read our [contribution](CONTRIBUTING.md) guide for more info.
If you're looking for something to get started with, tou can always follow our [issues page](https://github.com/PerimeterX/marshmallow/issues) and look for
[good first issue](https://github.com/PerimeterX/marshmallow/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) and
[help wanted](https://github.com/PerimeterX/marshmallow/issues?q=is%3Aissue+label%3A%22help+wanted%22+is%3Aopen) labels.
## Marshmallow Logo
Marshmallow logo and assets by [Adva Rom](https://www.linkedin.com/in/adva-rom-7a6738127/) are licensed under a Creative Commons Attribution 4.0 International License.

marshmallow-1.1.5/benchmark_test.go 0000664 0000000 0000000 00000014367 14450471353 0017405 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"encoding/json"
"github.com/ugorji/go/codec"
"testing"
)
// Unmarshal using marshmallow.
// This will not require any explicit coding and provide the best performance.
func BenchmarkMarshmallow(b *testing.B) {
EnableCache()
var v benchmarkParent
var result map[string]interface{}
var err error
b.ResetTimer()
for n := 0; n < b.N; n++ {
v = benchmarkParent{}
result, err = Unmarshal(benchmarkData, &v)
if err != nil {
b.Error("could not unmarshal data")
return
}
}
b.StopTimer()
validateBenchmarkStruct(b, &v)
validateBenchmarkTypedMap(b, result)
}
// Unmarshal twice - once into a struct and a second time into a map.
// This is fully native and requires no external dependencies.
// However, it obviously has huge implications over performance.
// This approach will be useful in case performance does not matter,
// and you do not wish to import any external dependencies.
func BenchmarkUnmarshalTwice(b *testing.B) {
var v benchmarkParent
var result map[string]interface{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
v = benchmarkParent{}
err := json.Unmarshal(benchmarkData, &v)
if err != nil {
b.Error("could not unmarshal data")
return
}
result = make(map[string]interface{})
err = json.Unmarshal(benchmarkData, &result)
if err != nil {
b.Error("could not unmarshal data")
return
}
}
b.StopTimer()
validateBenchmarkStruct(b, &v)
validateBenchmarkUntypedMap(b, result)
}
// Unmarshal into a raw map - and then populate the struct manually or using reflection.
// This method will be useful if you are willing to write more code to boost performance
// just by a bit and still avoid using external dependencies.
func BenchmarkUnmarshalRawMap(b *testing.B) {
var v benchmarkParent
var result map[string]interface{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
data := make(map[string]json.RawMessage)
err := json.Unmarshal(benchmarkData, &data)
if err != nil {
b.Error("could not unmarshal data")
return
}
v = benchmarkParent{}
result = make(map[string]interface{})
for key, value := range data {
switch key {
case "field1":
err = json.Unmarshal(value, &v.Field1)
if err != nil {
b.Error("could not unmarshal data")
return
}
result["field1"] = v.Field1
case "field2":
err = json.Unmarshal(value, &v.Field2)
if err != nil {
b.Error("could not unmarshal data")
return
}
result["field2"] = v.Field2
case "field3":
err = json.Unmarshal(value, &v.Field3)
if err != nil {
b.Error("could not unmarshal data")
return
}
result["field3"] = v.Field3
default:
var i interface{}
err = json.Unmarshal(value, &i)
if err != nil {
b.Error("could not unmarshal data")
return
}
result[key] = i
}
}
}
b.StopTimer()
validateBenchmarkStruct(b, &v)
validateBenchmarkTypedMap(b, result)
}
// Use go/codec or other libraries.
// This will boost performance a bit more but require explicit coding to hook struct fields
// into the map.
func BenchmarkGoCodec(b *testing.B) {
var v benchmarkParent
var result map[string]interface{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
v = benchmarkParent{}
result = make(map[string]interface{})
result["field1"] = &v.Field1
result["field2"] = &v.Field2
result["field3"] = &v.Field3
err := codec.NewDecoderBytes(benchmarkData, &codec.JsonHandle{}).Decode(&result)
if err != nil {
b.Error("could not unmarshal data")
return
}
}
b.StopTimer()
validateBenchmarkStruct(b, &v)
}
// Unmarshal using native JSON library. This will not provide any of map data at all.
// This is benchmarked here merely to get a general comparison of marshmallow runtime and performance.
func BenchmarkJSON(b *testing.B) {
b.ResetTimer()
var v benchmarkParent
for n := 0; n < b.N; n++ {
v = benchmarkParent{}
err := json.Unmarshal(benchmarkData, &v)
if err != nil {
b.Error("could not unmarshal data")
return
}
}
b.StopTimer()
validateBenchmarkStruct(b, &v)
}
// Unmarshal using marshmallow and skip populating struct.
// This is useful when you are only interested in populating typed fields into the map,
// but not interested in the resulting struct.
// This will further boost performance.
func BenchmarkMarshmallowWithSkipPopulateStruct(b *testing.B) {
EnableCache()
var v benchmarkParent
var result map[string]interface{}
var err error
b.ResetTimer()
for n := 0; n < b.N; n++ {
v = benchmarkParent{}
result, err = Unmarshal(benchmarkData, &v, WithSkipPopulateStruct(true))
if err != nil {
b.Error("could not unmarshal data")
return
}
}
b.StopTimer()
validateBenchmarkTypedMap(b, result)
}
var benchmarkData = []byte(`{"field1":"foo","field2":12,"field3":{"field1":"boo","field2":24},"field4":[1,24,false],"field5":false}`)
func validateBenchmarkStruct(b *testing.B, result *benchmarkParent) {
if result.Field1 == "foo" && result.Field2 == 12 && result.Field3.Field1 == "boo" && result.Field3.Field2 == 24 {
return
}
b.Error("invalid struct data")
}
func validateBenchmarkTypedMap(b *testing.B, m map[string]interface{}) {
if m["field1"] == "foo" &&
m["field2"] == 12 &&
m["field3"].(*benchmarkChild).Field1 == "boo" &&
m["field3"].(*benchmarkChild).Field2 == 24 &&
m["field4"].([]interface{})[0] == float64(1) &&
m["field4"].([]interface{})[1] == float64(24) &&
m["field4"].([]interface{})[2] == false &&
m["field5"] == false {
return
}
b.Error("invalid map data")
}
func validateBenchmarkUntypedMap(b *testing.B, m map[string]interface{}) {
if m["field1"] == "foo" &&
m["field2"] == float64(12) &&
m["field3"].(map[string]interface{})["field1"] == "boo" &&
m["field3"].(map[string]interface{})["field2"] == float64(24) &&
m["field4"].([]interface{})[0] == float64(1) &&
m["field4"].([]interface{})[1] == float64(24) &&
m["field4"].([]interface{})[2] == false &&
m["field5"] == false {
return
}
b.Error("invalid map data")
}
type benchmarkParent struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
Field3 *benchmarkChild `json:"field3"`
}
type benchmarkChild struct {
Field1 string `json:"field1"`
Field2 int `json:"field2"`
}
marshmallow-1.1.5/cache.go 0000664 0000000 0000000 00000004340 14450471353 0015445 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"reflect"
"sync"
)
// Cache allows unmarshalling to use a cached version of refection information about types.
// Cache interface follows the implementation of sync.Map, but you may wrap any cache implementation
// to match it. This allows you to control max cache size, eviction policies and any other caching aspect.
type Cache interface {
// Load returns the value stored in the map for a key, or nil if no value is present.
// The ok result indicates whether value was found in the map.
Load(key interface{}) (interface{}, bool)
// Store sets the value for a key.
Store(key, value interface{})
}
// EnableCustomCache enables unmarshalling cache. It allows reuse of refection information about types needed
// to perform the unmarshalling. A use of such cache can boost up unmarshalling by x1.4.
// Check out benchmark_test.go for an example.
//
// EnableCustomCache is not thread safe! Do not use it while performing unmarshalling, or it will
// cause an unsafe race condition. Typically, EnableCustomCache should be called once when the process boots.
//
// Caching is disabled by default. The use of this function allows enabling it and controlling the
// behavior of the cache. Typically, the use of sync.Map should be good enough. The caching mechanism
// stores a single map per struct type. If you plan to unmarshal a huge amount of distinct
// struct it may get to consume a lot of resources, in which case you have the control to choose
// the caching implementation you like and its setup.
func EnableCustomCache(c Cache) {
cache = c
}
// EnableCache enables unmarshalling cache with default implementation. More info at EnableCustomCache.
func EnableCache() {
EnableCustomCache(&sync.Map{})
}
var cache Cache
func cacheLookup(t reflect.Type) map[string]reflectionInfo {
if cache == nil {
return nil
}
value, exists := cache.Load(t)
if !exists {
return nil
}
result, _ := value.(map[string]reflectionInfo)
return result
}
func cacheStore(t reflect.Type, fields map[string]reflectionInfo) {
if cache == nil {
return
}
cache.Store(t, fields)
}
marshmallow-1.1.5/doc.go 0000664 0000000 0000000 00000000674 14450471353 0015155 0 ustar 00root root 0000000 0000000 /*
Package marshmallow provides a simple API to perform flexible and performant JSON unmarshalling.
Unlike other packages, marshmallow supports unmarshalling of some known and some unknown fields
with zero performance overhead nor extra coding needed. While unmarshalling,
marshmallow allows fully retaining the original data and access it via a typed struct and a
dynamic map.
https://github.com/perimeterx/marshmallow
*/
package marshmallow
marshmallow-1.1.5/errors.go 0000664 0000000 0000000 00000005433 14450471353 0015722 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"errors"
"fmt"
"github.com/mailru/easyjson/jlexer"
"reflect"
"strings"
)
var (
// ErrInvalidInput indicates the input JSON is invalid
ErrInvalidInput = errors.New("invalid JSON input")
// ErrInvalidValue indicates the target struct has invalid type
ErrInvalidValue = errors.New("unexpected non struct value")
)
// MultipleLexerError indicates one or more unmarshalling errors during JSON bytes decode
type MultipleLexerError struct {
Errors []*jlexer.LexerError
}
func (m *MultipleLexerError) Error() string {
errs := make([]string, len(m.Errors))
for i, lexerError := range m.Errors {
errs[i] = lexerError.Error()
}
return strings.Join(errs, ", ")
}
// MultipleError indicates one or more unmarshalling errors during JSON map decode
type MultipleError struct {
Errors []error
}
func (m *MultipleError) Error() string {
errs := make([]string, len(m.Errors))
for i, lexerError := range m.Errors {
errs[i] = lexerError.Error()
}
return strings.Join(errs, ", ")
}
// ParseError indicates a JSON map decode error
type ParseError struct {
Reason string
Path string
}
func (p *ParseError) Error() string {
return fmt.Sprintf("parse error: %s in %s", p.Reason, p.Path)
}
func newUnexpectedTypeParseError(expectedType reflect.Type, path []string) *ParseError {
return &ParseError{
Reason: fmt.Sprintf("expected type %s", externalTypeName(expectedType)),
Path: strings.Join(path, "."),
}
}
func newUnsupportedTypeParseError(unsupportedType reflect.Type, path []string) *ParseError {
return &ParseError{
Reason: fmt.Sprintf("unsupported type %s", externalTypeName(unsupportedType)),
Path: strings.Join(path, "."),
}
}
func addUnexpectedTypeLexerError(lexer *jlexer.Lexer, expectedType reflect.Type) {
lexer.AddNonFatalError(fmt.Errorf("expected type %s", externalTypeName(expectedType)))
}
func addUnsupportedTypeLexerError(lexer *jlexer.Lexer, unsupportedType reflect.Type) {
lexer.AddNonFatalError(fmt.Errorf("unsupported type %s", externalTypeName(unsupportedType)))
}
func externalTypeName(t reflect.Type) string {
switch t.Kind() {
case reflect.String:
return "string"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint,
reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32,
reflect.Float64, reflect.Complex64, reflect.Complex128:
return "number"
case reflect.Bool:
return "boolean"
case reflect.Array, reflect.Slice:
return "array"
case reflect.Interface:
return "any"
case reflect.Map, reflect.Struct:
return "object"
case reflect.Ptr:
return externalTypeName(t.Elem())
}
return "invalid"
}
marshmallow-1.1.5/example_test.go 0000664 0000000 0000000 00000025017 14450471353 0017100 0 ustar 00root root 0000000 0000000 package marshmallow_test
import (
"fmt"
"github.com/perimeterx/marshmallow"
"sync"
)
// ExampleBasicUnmarshal shows a basic example usage of marshmallow's unmarshalling capabilities
func ExampleBasicUnmarshal() {
// we have the following data
data := []byte(`{"name":"some name", "values": [1, 2, 3], "more_data": "some stuff I am not interested in..."}`)
// we want to read the "name" field, and modify the "values" field.
// we're not directly interested in the other fields, but we do want to retain them.
type exampleStruct struct {
Name string `json:"name"`
Values []int `json:"values"`
}
v := exampleStruct{}
// we pass in a struct containing the fields we're interested in,
// marshmallow will populate it and return a result map containing all data
result, err := marshmallow.Unmarshal(data, &v)
if err != nil {
panic(err)
}
fmt.Printf("Struct data: %+v\n", v)
fmt.Printf("Map data: %+v\n", result)
// now we can work with the struct data in a safe and maintainable manner
v.Values[0] = 42
fmt.Printf("Name is %s\n", v.Name)
// pointer value changes in the struct will also be visible from the map
// more info at https://github.com/PerimeterX/marshmallow/issues/23#issuecomment-1403409592
fmt.Printf("Map data after changes: %+v\n", result)
// Output:
// Struct data: {Name:some name Values:[1 2 3]}
// Map data: map[more_data:some stuff I am not interested in... name:some name values:[1 2 3]]
// Name is some name
// Map data after changes: map[more_data:some stuff I am not interested in... name:some name values:[42 2 3]]
}
// ExampleExcludeKnownFields shows how to use the WithExcludeKnownFieldsFromMap option to exclude struct fields
// from the result map. more info at https://github.com/PerimeterX/marshmallow/issues/16
func ExampleExcludeKnownFields() {
type exampleStruct struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}
// unmarshal with mode marshmallow.ModeExcludeKnownFieldsFromReturnedMap
// this will return unmarshalled result without known fields
v := exampleStruct{}
result, err := marshmallow.Unmarshal(
[]byte(`{"foo":"bar","boo":[1,2,3],"goo":"untyped"}`),
&v,
marshmallow.WithExcludeKnownFieldsFromMap(true),
)
fmt.Printf("v=%+v, result=%+v, err=%T\n", v, result, err)
// Output:
// v={Foo:bar Boo:[1 2 3]}, result=map[goo:untyped], err=
}
// ExampleJSONDataHandler shows how to capture nested unknown fields
// more info at https://github.com/PerimeterX/marshmallow/issues/15
func ExampleJSONDataHandler() {
type parentStruct struct {
Known string `json:"known"`
Nested childStruct `json:"nested"`
}
data := []byte(`{"known": "foo","unknown": "boo","nested": {"known": "goo","unknown": "doo"}}`)
p := &parentStruct{}
_, err := marshmallow.Unmarshal(data, p)
fmt.Printf("err: %v\n", err)
fmt.Printf("nested data: %+v\n", p.Nested.Data)
// Output:
// err:
// nested data: map[known:goo unknown:doo]
}
// ExampleCache shows how to enable marshmallow cache to boost up performance by reusing field type information.
// more info: https://github.com/PerimeterX/marshmallow/blob/22e3c7fe4423d7c5f317d95f84de524253e0aed3/cache.go#L35
func ExampleCache() {
// enable default cache
marshmallow.EnableCache()
type exampleStruct struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}
v := exampleStruct{}
_, _ = marshmallow.Unmarshal([]byte(`{"foo":"bar","boo":[1,2,3]}`), &v)
// enable custom cache, you can pass any implementation of the marshmallow.Cache interface
// this lets you control the size of the cache, eviction policy, or any other aspect of it.
marshmallow.EnableCustomCache(&sync.Map{})
}
// ExampleUnmarshalErrorHandling shows all error handling capabilities of marshmallow.Unmarshal
func ExampleUnmarshalErrorHandling() {
type exampleStruct struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}
// unmarshal with mode marshmallow.ModeFailOnFirstError and valid value
// this will finish unmarshalling and return a nil err
v := exampleStruct{}
result, err := marshmallow.Unmarshal([]byte(`{"foo":"bar","boo":[1,2,3]}`), &v)
fmt.Printf("ModeFailOnFirstError and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeFailOnFirstError and invalid value
// this will return nil result and an error
v = exampleStruct{}
result, err = marshmallow.Unmarshal([]byte(`{"foo":2,"boo":[1,2,3]}`), &v)
fmt.Printf("ModeFailOnFirstError and invalid value: result=%+v, err=%T\n", result, err)
// unmarshal with mode marshmallow.ModeAllowMultipleErrors and valid value
// this will finish unmarshalling and return a nil err
v = exampleStruct{}
result, err = marshmallow.Unmarshal(
[]byte(`{"foo":"bar","boo":[1,2,3]}`),
&v,
marshmallow.WithMode(marshmallow.ModeAllowMultipleErrors),
)
fmt.Printf("ModeAllowMultipleErrors and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeAllowMultipleErrors and invalid value
// this will return a partially populated result and an error
v = exampleStruct{}
result, err = marshmallow.Unmarshal(
[]byte(`{"foo":2,"boo":[1,2,3]}`),
&v,
marshmallow.WithMode(marshmallow.ModeAllowMultipleErrors),
)
fmt.Printf("ModeAllowMultipleErrors and invalid value: result=%+v, err=%T\n", result, err)
// unmarshal with mode marshmallow.ModeFailOverToOriginalValue and valid value
// this will finish unmarshalling and return a nil err
v = exampleStruct{}
result, err = marshmallow.Unmarshal(
[]byte(`{"foo":"bar","boo":[1,2,3]}`),
&v,
marshmallow.WithMode(marshmallow.ModeFailOverToOriginalValue),
)
fmt.Printf("ModeFailOverToOriginalValue and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeFailOverToOriginalValue and invalid value
// this will return a fully unmarshalled result, failing to the original invalid values, and an error
v = exampleStruct{}
result, err = marshmallow.Unmarshal(
[]byte(`{"foo":2,"boo":[1,2,3]}`),
&v,
marshmallow.WithMode(marshmallow.ModeFailOverToOriginalValue),
)
fmt.Printf("ModeFailOverToOriginalValue and invalid value: result=%+v, err=%T\n", result, err)
// Output:
// ModeFailOnFirstError and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeFailOnFirstError and invalid value: result=map[], err=*jlexer.LexerError
// ModeAllowMultipleErrors and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeAllowMultipleErrors and invalid value: result=map[boo:[1 2 3]], err=*marshmallow.MultipleLexerError
// ModeFailOverToOriginalValue and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeFailOverToOriginalValue and invalid value: result=map[boo:[1 2 3] foo:2], err=*marshmallow.MultipleLexerError
}
// ExampleUnmarshalFromJSONMap shows all error handling capabilities of marshmallow.UnmarshalFromJSONMap
func ExampleUnmarshalFromJSONMapErrorHandling() {
type exampleStruct struct {
Foo string `json:"foo"`
Boo []int `json:"boo"`
}
// unmarshal with mode marshmallow.ModeFailOnFirstError and valid value
// this will finish unmarshalling and return a nil err
v := exampleStruct{}
data := map[string]interface{}{"foo": "bar", "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err := marshmallow.UnmarshalFromJSONMap(data, &v)
fmt.Printf("ModeFailOnFirstError and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeFailOnFirstError and invalid value
// this will return nil result and an error
v = exampleStruct{}
data = map[string]interface{}{"foo": float64(2), "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err = marshmallow.UnmarshalFromJSONMap(data, &v)
fmt.Printf("ModeFailOnFirstError and invalid value: result=%+v, err=%T\n", result, err)
// unmarshal with mode marshmallow.ModeAllowMultipleErrors and valid value
// this will finish unmarshalling and return a nil err
v = exampleStruct{}
data = map[string]interface{}{"foo": "bar", "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err = marshmallow.UnmarshalFromJSONMap(
data,
&v,
marshmallow.WithMode(marshmallow.ModeAllowMultipleErrors),
)
fmt.Printf("ModeAllowMultipleErrors and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeAllowMultipleErrors and invalid value
// this will return a partially populated result and an error
v = exampleStruct{}
data = map[string]interface{}{"foo": float64(2), "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err = marshmallow.UnmarshalFromJSONMap(
data,
&v,
marshmallow.WithMode(marshmallow.ModeAllowMultipleErrors),
)
fmt.Printf("ModeAllowMultipleErrors and invalid value: result=%+v, err=%T\n", result, err)
// unmarshal with mode marshmallow.ModeFailOverToOriginalValue and valid value
// this will finish unmarshalling and return a nil err
v = exampleStruct{}
data = map[string]interface{}{"foo": "bar", "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err = marshmallow.UnmarshalFromJSONMap(
data,
&v,
marshmallow.WithMode(marshmallow.ModeFailOverToOriginalValue),
)
fmt.Printf("ModeFailOverToOriginalValue and valid value: v=%+v, result=%+v, err=%T\n", v, result, err)
// unmarshal with mode marshmallow.ModeFailOverToOriginalValue and invalid value
// this will return a fully unmarshalled result, failing to the original invalid values, and an error
v = exampleStruct{}
data = map[string]interface{}{"foo": float64(2), "boo": []interface{}{float64(1), float64(2), float64(3)}}
result, err = marshmallow.UnmarshalFromJSONMap(
data,
&v,
marshmallow.WithMode(marshmallow.ModeFailOverToOriginalValue),
)
fmt.Printf("ModeFailOverToOriginalValue and invalid value: result=%+v, err=%T\n", result, err)
// Output:
// ModeFailOnFirstError and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeFailOnFirstError and invalid value: result=map[], err=*marshmallow.ParseError
// ModeAllowMultipleErrors and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeAllowMultipleErrors and invalid value: result=map[boo:[1 2 3]], err=*marshmallow.MultipleError
// ModeFailOverToOriginalValue and valid value: v={Foo:bar Boo:[1 2 3]}, result=map[boo:[1 2 3] foo:bar], err=
// ModeFailOverToOriginalValue and invalid value: result=map[boo:[1 2 3] foo:2], err=*marshmallow.MultipleError
}
type childStruct struct {
Known string `json:"known"`
Data map[string]interface{} `json:"-"`
}
func (c *childStruct) HandleJSONData(data map[string]interface{}) error {
c.Data = data
return nil
}
marshmallow-1.1.5/go.mod 0000664 0000000 0000000 00000000335 14450471353 0015161 0 ustar 00root root 0000000 0000000 module github.com/perimeterx/marshmallow
go 1.17
require (
github.com/go-test/deep v1.0.8
github.com/mailru/easyjson v0.7.7
github.com/ugorji/go/codec v1.2.7
)
require github.com/josharian/intern v1.0.0 // indirect
marshmallow-1.1.5/go.sum 0000664 0000000 0000000 00000001507 14450471353 0015210 0 ustar 00root root 0000000 0000000 github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
marshmallow-1.1.5/options.go 0000664 0000000 0000000 00000007243 14450471353 0016102 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
// Mode dictates the unmarshalling mode.
// Each mode is self documented below.
type Mode uint8
const (
// ModeFailOnFirstError is the default mode. It makes unmarshalling terminate
// immediately on any kind of error. This error will then be returned.
ModeFailOnFirstError Mode = iota
// ModeAllowMultipleErrors mode makes unmarshalling keep decoding even if
// errors are encountered. In case of such error, the erroneous value will be omitted from the result.
// Eventually, all errors will all be returned, alongside the partial result.
ModeAllowMultipleErrors
// ModeFailOverToOriginalValue mode makes unmarshalling keep decoding even if
// errors are encountered. In case of such error, the original external value be placed in the
// result data, even though it does not meet the schematic requirements.
// Eventually, all errors will be returned, alongside the full result. Note that the result map
// will contain values that do not match the struct schema.
ModeFailOverToOriginalValue
)
// WithMode is an UnmarshalOption function to set the unmarshalling mode.
func WithMode(mode Mode) UnmarshalOption {
return func(options *unmarshalOptions) {
options.mode = mode
}
}
// WithSkipPopulateStruct is an UnmarshalOption function to set the skipPopulateStruct option.
// Skipping populate struct is set to false by default.
// If you do not intend to use the struct value once unmarshalling is finished, set this
// option to true to boost performance. This would mean the struct fields will not be set
// with values, but rather it will only be used as the target schema when populating the result map.
func WithSkipPopulateStruct(skipPopulateStruct bool) UnmarshalOption {
return func(options *unmarshalOptions) {
options.skipPopulateStruct = skipPopulateStruct
}
}
// WithExcludeKnownFieldsFromMap is an UnmarshalOption function to set the excludeKnownFieldsFromMap option.
// Exclude known fields flag is set to false by default.
// When the flag is set to true, fields specified in the input struct (known fields) will be excluded from the result map
func WithExcludeKnownFieldsFromMap(excludeKnownFields bool) UnmarshalOption {
return func(options *unmarshalOptions) {
options.excludeKnownFieldsFromMap = excludeKnownFields
}
}
type UnmarshalOption func(*unmarshalOptions)
type unmarshalOptions struct {
mode Mode
skipPopulateStruct bool
excludeKnownFieldsFromMap bool
}
func buildUnmarshalOptions(options []UnmarshalOption) *unmarshalOptions {
result := &unmarshalOptions{}
for _, option := range options {
option(result)
}
return result
}
// JSONDataErrorHandler allow types to handle JSON data as maps.
// Types should implement this interface if they wish to act on the map representation of parsed JSON input.
// This is mainly used to allow nested objects to capture unknown fields and leverage marshmallow's abilities.
// If HandleJSONData returns an error, it will be propagated as an unmarshal error
type JSONDataErrorHandler interface {
HandleJSONData(data map[string]interface{}) error
}
// Deprecated: use JSONDataErrorHandler instead
type JSONDataHandler interface {
HandleJSONData(data map[string]interface{})
}
func asJSONDataHandler(value interface{}) (func(map[string]interface{}) error, bool) {
if handler, ok := value.(JSONDataErrorHandler); ok {
return handler.HandleJSONData, true
}
if handler, ok := value.(JSONDataHandler); ok {
return func(m map[string]interface{}) error {
handler.HandleJSONData(m)
return nil
}, true
}
return nil, false
}
marshmallow-1.1.5/reflection.go 0000664 0000000 0000000 00000010345 14450471353 0016536 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"encoding/json"
"reflect"
"strings"
)
var unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
type reflectionInfo struct {
path []int
t reflect.Type
}
func (r reflectionInfo) field(target reflect.Value) reflect.Value {
current := target
for _, i := range r.path {
current = current.Field(i)
}
return current
}
func mapStructFields(target interface{}) map[string]reflectionInfo {
t := reflectStructType(target)
result := cacheLookup(t)
if result != nil {
return result
}
result = make(map[string]reflectionInfo, t.NumField())
mapTypeFields(t, result, nil)
cacheStore(t, result)
return result
}
func mapTypeFields(t reflect.Type, result map[string]reflectionInfo, path []int) {
num := t.NumField()
for i := 0; i < num; i++ {
field := t.Field(i)
fieldPath := append(path, i)
if field.Anonymous && field.Type.Kind() == reflect.Struct {
mapTypeFields(field.Type, result, fieldPath)
continue
}
name := field.Tag.Get("json")
if name == "" || name == "-" {
continue
}
if index := strings.Index(name, ","); index > -1 {
name = name[:index]
}
result[name] = reflectionInfo{
path: fieldPath,
t: field.Type,
}
}
}
func reflectStructValue(target interface{}) reflect.Value {
v := reflect.ValueOf(target)
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v
}
func reflectStructType(target interface{}) reflect.Type {
t := reflect.TypeOf(target)
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
var primitiveConverters = map[reflect.Kind]func(v interface{}) (interface{}, bool){
reflect.Bool: func(v interface{}) (interface{}, bool) {
res, ok := v.(bool)
return res, ok
},
reflect.Int: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return int(res), true
}
return v, false
},
reflect.Int8: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return int8(res), true
}
return v, false
},
reflect.Int16: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return int16(res), true
}
return v, false
},
reflect.Int32: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return int32(res), true
}
return v, false
},
reflect.Int64: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return int64(res), true
}
return v, false
},
reflect.Uint: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return uint(res), true
}
return v, false
},
reflect.Uint8: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return uint8(res), true
}
return v, false
},
reflect.Uint16: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return uint16(res), true
}
return v, false
},
reflect.Uint32: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return uint32(res), true
}
return v, false
},
reflect.Uint64: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return uint64(res), true
}
return v, false
},
reflect.Float32: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return float32(res), true
}
return v, false
},
reflect.Float64: func(v interface{}) (interface{}, bool) {
res, ok := v.(float64)
if ok {
return res, true
}
return v, false
},
reflect.Interface: func(v interface{}) (interface{}, bool) {
return v, true
},
reflect.String: func(v interface{}) (interface{}, bool) {
res, ok := v.(string)
return res, ok
},
}
func assignValue(field reflect.Value, value interface{}) {
if value == nil {
return
}
reflectValue := reflect.ValueOf(value)
if reflectValue.Type().AssignableTo(field.Type()) {
field.Set(reflectValue)
}
}
func isValidValue(v interface{}) bool {
value := reflect.ValueOf(v)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Struct && !value.IsNil()
}
func safeReflectValue(t reflect.Type, v interface{}) reflect.Value {
if v == nil {
return reflect.Zero(t)
}
return reflect.ValueOf(v)
}
marshmallow-1.1.5/unmarshal.go 0000664 0000000 0000000 00000024163 14450471353 0016401 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"encoding/json"
"github.com/mailru/easyjson/jlexer"
"reflect"
)
// Unmarshal parses the JSON-encoded object in data and stores the values
// in the struct pointed to by v and in the returned map.
// If v is nil or not a pointer to a struct, Unmarshal returns an ErrInvalidValue.
// If data is not a valid JSON or not a JSON object Unmarshal returns an ErrInvalidInput.
//
// Unmarshal follows the rules of json.Unmarshal with the following exceptions:
// - All input fields are stored in the resulting map, including fields that do not exist in the
// struct pointed by v.
// - Unmarshal only operates on JSON object inputs. It will reject all other types of input
// by returning ErrInvalidInput.
// - Unmarshal only operates on struct values. It will reject all other types of v by
// returning ErrInvalidValue.
// - Unmarshal supports three types of Mode values. Each mode is self documented and affects
// how Unmarshal behaves.
func Unmarshal(data []byte, v interface{}, options ...UnmarshalOption) (map[string]interface{}, error) {
if !isValidValue(v) {
return nil, ErrInvalidValue
}
opts := buildUnmarshalOptions(options)
useMultipleErrors := opts.mode == ModeAllowMultipleErrors || opts.mode == ModeFailOverToOriginalValue
d := &decoder{options: opts, lexer: &jlexer.Lexer{Data: data, UseMultipleErrors: useMultipleErrors}}
result := make(map[string]interface{})
if d.lexer.IsNull() {
d.lexer.Skip()
} else if !d.lexer.IsDelim('{') {
return nil, ErrInvalidInput
} else {
d.populateStruct(false, v, result)
}
d.lexer.Consumed()
if useMultipleErrors {
errors := d.lexer.GetNonFatalErrors()
if len(errors) == 0 {
return result, nil
}
return result, &MultipleLexerError{Errors: errors}
}
err := d.lexer.Error()
if err != nil {
return nil, err
}
return result, nil
}
type decoder struct {
options *unmarshalOptions
lexer *jlexer.Lexer
}
func (d *decoder) populateStruct(forcePopulate bool, structInstance interface{}, result map[string]interface{}) (interface{}, bool) {
doPopulate := !d.options.skipPopulateStruct || forcePopulate
var structValue reflect.Value
if doPopulate {
structValue = reflectStructValue(structInstance)
}
fields := mapStructFields(structInstance)
var clone map[string]interface{}
if d.options.mode == ModeFailOverToOriginalValue {
clone = make(map[string]interface{}, len(fields))
}
d.lexer.Delim('{')
for !d.lexer.IsDelim('}') {
key := d.lexer.UnsafeFieldName(false)
d.lexer.WantColon()
refInfo, exists := fields[key]
if exists {
value, isValidType := d.valueByReflectType(refInfo.t)
if isValidType {
if value != nil && doPopulate {
field := refInfo.field(structValue)
assignValue(field, value)
}
if !d.options.excludeKnownFieldsFromMap {
if result != nil {
result[key] = value
}
if clone != nil {
clone[key] = value
}
}
} else {
switch d.options.mode {
case ModeFailOnFirstError:
return nil, false
case ModeFailOverToOriginalValue:
if !forcePopulate {
result[key] = value
} else {
clone[key] = value
d.lexer.WantComma()
d.drainLexerMap(clone)
return clone, false
}
}
}
} else {
value := d.lexer.Interface()
if result != nil {
result[key] = value
}
if clone != nil {
clone[key] = value
}
}
d.lexer.WantComma()
}
d.lexer.Delim('}')
return structInstance, true
}
func (d *decoder) valueByReflectType(t reflect.Type) (interface{}, bool) {
if t.Implements(unmarshalerType) {
result := reflect.New(t.Elem()).Interface()
d.valueFromCustomUnmarshaler(result.(json.Unmarshaler))
return result, true
}
if reflect.PtrTo(t).Implements(unmarshalerType) {
value := reflect.New(t)
d.valueFromCustomUnmarshaler(value.Interface().(json.Unmarshaler))
return value.Elem().Interface(), true
}
kind := t.Kind()
if converter := primitiveConverters[kind]; converter != nil {
v := d.lexer.Interface()
if v == nil {
return nil, true
}
converted, ok := converter(v)
if !ok {
addUnexpectedTypeLexerError(d.lexer, t)
return v, false
}
return converted, true
}
switch kind {
case reflect.Slice:
return d.buildSlice(t)
case reflect.Array:
return d.buildArray(t)
case reflect.Map:
return d.buildMap(t)
case reflect.Struct:
value, valid := d.buildStruct(t)
if value == nil {
return nil, valid
}
if !valid {
return value, false
}
return reflect.ValueOf(value).Elem().Interface(), valid
case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct {
return d.buildStruct(t.Elem())
}
value, valid := d.valueByReflectType(t.Elem())
if value == nil {
return nil, valid
}
if !valid {
return value, false
}
result := reflect.New(reflect.TypeOf(value))
result.Elem().Set(reflect.ValueOf(value))
return result.Interface(), valid
}
addUnsupportedTypeLexerError(d.lexer, t)
return nil, false
}
func (d *decoder) buildSlice(sliceType reflect.Type) (interface{}, bool) {
if d.lexer.IsNull() {
d.lexer.Skip()
return nil, true
}
if !d.lexer.IsDelim('[') {
addUnexpectedTypeLexerError(d.lexer, sliceType)
return d.lexer.Interface(), false
}
elemType := sliceType.Elem()
d.lexer.Delim('[')
var sliceValue reflect.Value
if !d.lexer.IsDelim(']') {
sliceValue = reflect.MakeSlice(sliceType, 0, 4)
} else {
sliceValue = reflect.MakeSlice(sliceType, 0, 0)
}
for !d.lexer.IsDelim(']') {
current, valid := d.valueByReflectType(elemType)
if !valid {
if d.options.mode != ModeFailOverToOriginalValue {
d.drainLexerArray(nil)
return nil, true
}
result := d.cloneReflectArray(sliceValue, -1)
result = append(result, current)
return d.drainLexerArray(result), true
}
sliceValue = reflect.Append(sliceValue, safeReflectValue(elemType, current))
d.lexer.WantComma()
}
d.lexer.Delim(']')
return sliceValue.Interface(), true
}
func (d *decoder) buildArray(arrayType reflect.Type) (interface{}, bool) {
if d.lexer.IsNull() {
d.lexer.Skip()
return nil, true
}
if !d.lexer.IsDelim('[') {
addUnexpectedTypeLexerError(d.lexer, arrayType)
return d.lexer.Interface(), false
}
elemType := arrayType.Elem()
arrayValue := reflect.New(arrayType).Elem()
d.lexer.Delim('[')
for i := 0; !d.lexer.IsDelim(']'); i++ {
current, valid := d.valueByReflectType(elemType)
if !valid {
if d.options.mode != ModeFailOverToOriginalValue {
d.drainLexerArray(nil)
return nil, true
}
result := d.cloneReflectArray(arrayValue, i)
result = append(result, current)
return d.drainLexerArray(result), true
}
if current != nil {
arrayValue.Index(i).Set(reflect.ValueOf(current))
}
d.lexer.WantComma()
}
d.lexer.Delim(']')
return arrayValue.Interface(), true
}
func (d *decoder) buildMap(mapType reflect.Type) (interface{}, bool) {
if d.lexer.IsNull() {
d.lexer.Skip()
return nil, true
}
if !d.lexer.IsDelim('{') {
addUnexpectedTypeLexerError(d.lexer, mapType)
return d.lexer.Interface(), false
}
d.lexer.Delim('{')
keyType := mapType.Key()
valueType := mapType.Elem()
mapValue := reflect.MakeMap(mapType)
for !d.lexer.IsDelim('}') {
key, valid := d.valueByReflectType(keyType)
if !valid {
if d.options.mode != ModeFailOverToOriginalValue {
d.lexer.WantColon()
d.lexer.Interface()
d.lexer.WantComma()
d.drainLexerMap(make(map[string]interface{}))
return nil, true
}
strKey, _ := key.(string)
d.lexer.WantColon()
value := d.lexer.Interface()
result := d.cloneReflectMap(mapValue)
result[strKey] = value
d.lexer.WantComma()
d.drainLexerMap(result)
return result, true
}
d.lexer.WantColon()
value, valid := d.valueByReflectType(valueType)
if !valid {
if d.options.mode != ModeFailOverToOriginalValue {
d.lexer.WantComma()
d.drainLexerMap(make(map[string]interface{}))
return nil, true
}
strKey, _ := key.(string)
result := d.cloneReflectMap(mapValue)
result[strKey] = value
d.lexer.WantComma()
d.drainLexerMap(result)
return result, true
}
mapValue.SetMapIndex(safeReflectValue(keyType, key), safeReflectValue(valueType, value))
d.lexer.WantComma()
}
d.lexer.Delim('}')
return mapValue.Interface(), true
}
func (d *decoder) buildStruct(structType reflect.Type) (interface{}, bool) {
if d.lexer.IsNull() {
d.lexer.Skip()
return nil, true
}
if !d.lexer.IsDelim('{') {
addUnexpectedTypeLexerError(d.lexer, structType)
return d.lexer.Interface(), false
}
value := reflect.New(structType).Interface()
handler, ok := asJSONDataHandler(value)
if !ok {
return d.populateStruct(true, value, nil)
}
data := make(map[string]interface{})
result, valid := d.populateStruct(true, value, data)
if !valid {
return result, false
}
err := handler(data)
if err != nil {
d.lexer.AddNonFatalError(err)
return result, false
}
return result, true
}
func (d *decoder) valueFromCustomUnmarshaler(unmarshaler json.Unmarshaler) {
data := d.lexer.Raw()
if !d.lexer.Ok() {
return
}
err := unmarshaler.UnmarshalJSON(data)
if err != nil {
d.lexer.AddNonFatalError(err)
}
}
func (d *decoder) cloneReflectArray(value reflect.Value, length int) []interface{} {
if length == -1 {
length = value.Len()
}
result := make([]interface{}, length)
for i := 0; i < length; i++ {
result[i] = value.Index(i).Interface()
}
return result
}
func (d *decoder) cloneReflectMap(mapValue reflect.Value) map[string]interface{} {
l := mapValue.Len()
result := make(map[string]interface{}, l)
for _, key := range mapValue.MapKeys() {
value := mapValue.MapIndex(key)
strKey, _ := key.Interface().(string)
result[strKey] = value.Interface()
}
return result
}
func (d *decoder) drainLexerArray(target []interface{}) interface{} {
d.lexer.WantComma()
for !d.lexer.IsDelim(']') {
current := d.lexer.Interface()
target = append(target, current)
d.lexer.WantComma()
}
d.lexer.Delim(']')
return target
}
func (d *decoder) drainLexerMap(target map[string]interface{}) {
for !d.lexer.IsDelim('}') {
key := d.lexer.String()
d.lexer.WantColon()
value := d.lexer.Interface()
target[key] = value
d.lexer.WantComma()
}
d.lexer.Delim('}')
}
marshmallow-1.1.5/unmarshal_from_json_map.go 0000664 0000000 0000000 00000021176 14450471353 0021313 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"reflect"
)
// UnmarshalerFromJSONMap is the interface implemented by types
// that can unmarshal a JSON description of themselves.
// In case you want to implement custom unmarshalling, json.Unmarshaler only supports
// receiving the data as []byte. However, while unmarshalling from JSON map,
// the data is not available as a raw []byte and converting to it will significantly
// hurt performance. Thus, if you wish to implement a custom unmarshalling on a type
// that is being unmarshalled from a JSON map, you need to implement
// UnmarshalerFromJSONMap interface.
type UnmarshalerFromJSONMap interface {
UnmarshalJSONFromMap(data interface{}) error
}
// UnmarshalFromJSONMap parses the JSON map data and stores the values
// in the struct pointed to by v and in the returned map.
// If v is nil or not a pointer to a struct, UnmarshalFromJSONMap returns an ErrInvalidValue.
//
// UnmarshalFromJSONMap follows the rules of json.Unmarshal with the following exceptions:
// - All input fields are stored in the resulting map, including fields that do not exist in the
// struct pointed by v.
// - UnmarshalFromJSONMap receive a JSON map instead of raw bytes. The given input map is assumed
// to be a JSON map, meaning it should only contain the following types: bool, string, float64,
// []interface, and map[string]interface{}. Other types will cause decoding to return unexpected results.
// - UnmarshalFromJSONMap only operates on struct values. It will reject all other types of v by
// returning ErrInvalidValue.
// - UnmarshalFromJSONMap supports three types of Mode values. Each mode is self documented and affects
// how UnmarshalFromJSONMap behaves.
func UnmarshalFromJSONMap(data map[string]interface{}, v interface{}, options ...UnmarshalOption) (map[string]interface{}, error) {
if !isValidValue(v) {
return nil, ErrInvalidValue
}
opts := buildUnmarshalOptions(options)
d := &mapDecoder{options: opts}
result := make(map[string]interface{})
if data != nil {
d.populateStruct(false, nil, data, v, result)
}
if opts.mode == ModeAllowMultipleErrors || opts.mode == ModeFailOverToOriginalValue {
if len(d.errs) == 0 {
return result, nil
}
return result, &MultipleError{Errors: d.errs}
}
if d.err != nil {
return nil, d.err
}
return result, nil
}
var unmarshalerFromJSONMapType = reflect.TypeOf((*UnmarshalerFromJSONMap)(nil)).Elem()
type mapDecoder struct {
options *unmarshalOptions
err error
errs []error
}
func (m *mapDecoder) populateStruct(forcePopulate bool, path []string, data map[string]interface{}, structInstance interface{}, result map[string]interface{}) (interface{}, bool) {
doPopulate := !m.options.skipPopulateStruct || forcePopulate
var structValue reflect.Value
if doPopulate {
structValue = reflectStructValue(structInstance)
}
fields := mapStructFields(structInstance)
for key, inputValue := range data {
refInfo, exists := fields[key]
if exists {
value, isValidType := m.valueByReflectType(append(path, key), inputValue, refInfo.t)
if isValidType {
if value != nil && doPopulate {
field := refInfo.field(structValue)
assignValue(field, value)
}
if !m.options.excludeKnownFieldsFromMap {
if result != nil {
result[key] = value
}
}
} else {
switch m.options.mode {
case ModeFailOnFirstError:
return nil, false
case ModeFailOverToOriginalValue:
if !forcePopulate {
result[key] = value
} else {
return data, false
}
}
}
} else {
if result != nil {
result[key] = inputValue
}
}
}
return structInstance, true
}
func (m *mapDecoder) valueByReflectType(path []string, v interface{}, t reflect.Type) (interface{}, bool) {
if t.Implements(unmarshalerFromJSONMapType) {
result := reflect.New(t.Elem()).Interface()
m.valueFromCustomUnmarshaler(v, result.(UnmarshalerFromJSONMap))
return result, true
}
if reflect.PtrTo(t).Implements(unmarshalerFromJSONMapType) {
value := reflect.New(t)
m.valueFromCustomUnmarshaler(v, value.Interface().(UnmarshalerFromJSONMap))
return value.Elem().Interface(), true
}
kind := t.Kind()
if converter := primitiveConverters[kind]; converter != nil {
if v == nil {
return nil, true
}
converted, ok := converter(v)
if !ok {
m.addError(newUnexpectedTypeParseError(t, path))
return v, false
}
return converted, true
}
switch kind {
case reflect.Slice:
return m.buildSlice(path, v, t)
case reflect.Array:
return m.buildArray(path, v, t)
case reflect.Map:
return m.buildMap(path, v, t)
case reflect.Struct:
value, valid := m.buildStruct(path, v, t)
if value == nil {
return nil, valid
}
if !valid {
return value, false
}
return reflect.ValueOf(value).Elem().Interface(), valid
case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct {
return m.buildStruct(path, v, t.Elem())
}
value, valid := m.valueByReflectType(path, v, t.Elem())
if value == nil {
return nil, valid
}
if !valid {
return value, false
}
result := reflect.New(reflect.TypeOf(value))
result.Elem().Set(reflect.ValueOf(value))
return result.Interface(), valid
}
m.addError(newUnsupportedTypeParseError(t, path))
return nil, false
}
func (m *mapDecoder) buildSlice(path []string, v interface{}, sliceType reflect.Type) (interface{}, bool) {
if v == nil {
return nil, true
}
arr, ok := v.([]interface{})
if !ok {
m.addError(newUnexpectedTypeParseError(sliceType, path))
return v, false
}
elemType := sliceType.Elem()
var sliceValue reflect.Value
if len(arr) > 0 {
sliceValue = reflect.MakeSlice(sliceType, 0, 4)
} else {
sliceValue = reflect.MakeSlice(sliceType, 0, 0)
}
for _, element := range arr {
current, valid := m.valueByReflectType(path, element, elemType)
if !valid {
if m.options.mode != ModeFailOverToOriginalValue {
return nil, true
}
return v, true
}
sliceValue = reflect.Append(sliceValue, safeReflectValue(elemType, current))
}
return sliceValue.Interface(), true
}
func (m *mapDecoder) buildArray(path []string, v interface{}, arrayType reflect.Type) (interface{}, bool) {
if v == nil {
return nil, true
}
arr, ok := v.([]interface{})
if !ok {
m.addError(newUnexpectedTypeParseError(arrayType, path))
return v, false
}
elemType := arrayType.Elem()
arrayValue := reflect.New(arrayType).Elem()
for i, element := range arr {
current, valid := m.valueByReflectType(path, element, elemType)
if !valid {
if m.options.mode != ModeFailOverToOriginalValue {
return nil, true
}
return v, true
}
if current != nil {
arrayValue.Index(i).Set(reflect.ValueOf(current))
}
}
return arrayValue.Interface(), true
}
func (m *mapDecoder) buildMap(path []string, v interface{}, mapType reflect.Type) (interface{}, bool) {
if v == nil {
return nil, true
}
mp, ok := v.(map[string]interface{})
if !ok {
m.addError(newUnexpectedTypeParseError(mapType, path))
return v, false
}
keyType := mapType.Key()
valueType := mapType.Elem()
mapValue := reflect.MakeMap(mapType)
for inputKey, inputValue := range mp {
keyPath := append(path, inputKey)
key, valid := m.valueByReflectType(keyPath, inputKey, keyType)
if !valid {
if m.options.mode != ModeFailOverToOriginalValue {
return nil, true
}
return v, true
}
value, valid := m.valueByReflectType(keyPath, inputValue, valueType)
if !valid {
if m.options.mode != ModeFailOverToOriginalValue {
return nil, true
}
return v, true
}
mapValue.SetMapIndex(safeReflectValue(keyType, key), safeReflectValue(valueType, value))
}
return mapValue.Interface(), true
}
func (m *mapDecoder) buildStruct(path []string, v interface{}, structType reflect.Type) (interface{}, bool) {
if v == nil {
return nil, true
}
mp, ok := v.(map[string]interface{})
if !ok {
m.addError(newUnexpectedTypeParseError(structType, path))
return v, false
}
value := reflect.New(structType).Interface()
handler, ok := asJSONDataHandler(value)
if !ok {
return m.populateStruct(true, path, mp, value, nil)
}
data := make(map[string]interface{})
result, valid := m.populateStruct(true, path, mp, value, data)
if !valid {
return result, false
}
err := handler(data)
if err != nil {
m.addError(err)
return result, false
}
return result, true
}
func (m *mapDecoder) valueFromCustomUnmarshaler(data interface{}, unmarshaler UnmarshalerFromJSONMap) {
err := unmarshaler.UnmarshalJSONFromMap(data)
if err != nil {
m.addError(err)
}
}
func (m *mapDecoder) addError(err error) {
if m.options.mode == ModeFailOnFirstError {
m.err = err
} else {
m.errs = append(m.errs, err)
}
}
marshmallow-1.1.5/unmarshal_from_json_map_test.go 0000664 0000000 0000000 00000243536 14450471353 0022360 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"github.com/go-test/deep"
"reflect"
"strings"
"testing"
)
func TestUnmarshalFromJSONMapInputVariations(t *testing.T) {
EnableCache()
tests := []struct {
name string
mode Mode
expectedErr bool
expectedResult bool
structModifier func(*parentStruct)
inputMapModifier func(map[string]interface{})
expectedMapModifier func(map[string]interface{})
}{
{
name: "ModeFailOnFirstError_happy_flow",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_zero_struct_value",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_null_on_struct",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeFailOnFirstError_null_on_string",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeFailOnFirstError_null_on_slice",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeFailOnFirstError_null_on_array",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeFailOnFirstError_null_on_map",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOnFirstError_invalid_struct_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_ptr_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_ptr_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_primitive_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_ptr_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_bool_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int8_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int16_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint8_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint16_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_bool_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int8_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int16_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint8_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint16_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_slice_element",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_array_element",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_map_entry",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_happy_flow",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_zero_struct_value",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_null_on_struct",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeAllowMultipleErrors_null_on_string",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeAllowMultipleErrors_null_on_slice",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeAllowMultipleErrors_null_on_array",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeAllowMultipleErrors_null_on_map",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field1")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField2 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field2")
},
},
{
name: "ModeAllowMultipleErrors_invalid_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field3")
},
},
{
name: "ModeAllowMultipleErrors_invalid_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field4")
},
},
{
name: "ModeAllowMultipleErrors_invalid_ptr_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField5 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field5")
},
},
{
name: "ModeAllowMultipleErrors_invalid_ptr_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField6 = [4]*childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field6")
},
},
{
name: "ModeAllowMultipleErrors_invalid_primitive_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field7")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField8 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field8")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_ptr_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField9 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field9")
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField1 = ""
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeAllowMultipleErrors_invalid_bool_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField2 = false
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField2 = false
},
},
{
name: "ModeAllowMultipleErrors_invalid_int_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField3 = 0
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField3 = 0
},
},
{
name: "ModeAllowMultipleErrors_invalid_int8_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField4 = int8(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField4 = int8(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int16_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField5 = int16(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField5 = int16(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField6 = int32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField6 = int32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField7 = int64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField7 = int64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField8 = uint(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField8 = uint(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint8_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField9 = uint8(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField9 = uint8(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint16_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField10 = uint16(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField10 = uint16(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField11 = uint32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField11 = uint32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField12 = uint64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField12 = uint64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_float32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField13 = float32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField13 = float32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_float64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField14 = float64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField14 = float64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField15 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField15 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_bool_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField16 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField16 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField17 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField17 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int8_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField18 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField18 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int16_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField19 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField19 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField20 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField20 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField21 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField21 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField22 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField22 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint8_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField23 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField23 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint16_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField24 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField24 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField25 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField25 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField26 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField26 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_float32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField27 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField27 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_float64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField28 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField28 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField30 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField31 = [4]string{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeAllowMultipleErrors_invalid_slice_element",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_array_element",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_map_entry",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_happy_flow",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOverToOriginalValue_zero_struct_value",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOverToOriginalValue_null_on_struct",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_null_on_string",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeFailOverToOriginalValue_null_on_slice",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeFailOverToOriginalValue_null_on_array",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeFailOverToOriginalValue_null_on_map",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField2 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_ptr_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField5 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_ptr_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField6 = [4]*childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_primitive_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField8 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_ptr_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField9 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_bool_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int8_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int16_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint8_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint16_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_bool_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int8_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int16_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint8_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint16_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_slice_element",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_array_element",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_map_entry",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": float64(12), "boo": "c"}
},
},
{
name: "nested_unknown_fields",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{
ChildField1: "a",
}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = map[string]interface{}{"child_field1": "a", "foo": "f", "boo": "b"}
},
expectedMapModifier: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expectedStruct := buildParentStruct()
if tt.structModifier != nil {
tt.structModifier(expectedStruct)
}
input := toMap(expectedStruct)
for k, v := range extraData {
input[k] = v
}
if tt.inputMapModifier != nil {
tt.inputMapModifier(input)
}
actualStruct := &parentStruct{}
actualMap, err := UnmarshalFromJSONMap(input, actualStruct, WithMode(tt.mode))
if (err != nil) != tt.expectedErr {
t.Errorf("Unmarshal() error = %v, expectedErr %v", err, tt.expectedErr)
}
if tt.expectedResult {
expectedStruct.ParentField10.CustomField = "UnmarshalJSON called"
expectedStruct.ParentField11.CustomField = "UnmarshalJSON called"
if diff := deep.Equal(actualStruct, expectedStruct); diff != nil {
t.Errorf("Unmarshal() struct mismatch (actual, expected):\n%s", strings.Join(diff, "\n"))
}
expectedMap := make(map[string]interface{})
for k, v := range extraData {
expectedMap[k] = v
}
structValue := reflectStructValue(actualStruct)
for name, refInfo := range mapStructFields(actualStruct) {
field := refInfo.field(structValue)
expectedMap[name] = field.Interface()
}
if tt.expectedMapModifier != nil {
tt.expectedMapModifier(expectedMap)
}
if tt.mode == ModeFailOverToOriginalValue {
normalizeMapTypes(actualMap)
}
if diff := deep.Equal(actualMap, expectedMap); diff != nil {
t.Errorf("Unmarshal() map mismatch (actual, expected):\n%s", strings.Join(diff, "\n"))
}
} else {
if reflect.DeepEqual(actualStruct, expectedStruct) {
t.Error("Unmarshal() expected parsing to break before finished")
}
if actualMap != nil {
t.Errorf("Unmarshal() expected actual map to not exist")
}
}
})
}
}
func TestUnmarshalFromJSONMapSpecialInput(t *testing.T) {
tests := []struct {
name string
input map[string]interface{}
v interface{}
mode Mode
result bool
errValidator func(error) bool
}{
{
name: "invalid_value",
input: map[string]interface{}{},
v: "",
mode: ModeFailOnFirstError,
result: false,
errValidator: func(err error) bool {
return err == ErrInvalidValue
},
},
{
name: "null_input",
input: nil,
v: &parentStruct{},
mode: ModeFailOnFirstError,
result: true,
errValidator: func(err error) bool {
return err == nil
},
},
{
name: "ModeFailOnFirstError_custom_unmarshal_failing",
input: map[string]interface{}{"field": ""},
v: &failingCustomUnmarshalerParent{},
mode: ModeFailOnFirstError,
result: false,
errValidator: func(err error) bool {
return err.Error() == "failing"
},
},
{
name: "ModeAllowMultipleErrors_custom_unmarshal_failing",
input: map[string]interface{}{"field": ""},
v: &failingCustomUnmarshalerParent{},
mode: ModeAllowMultipleErrors,
result: true,
errValidator: func(err error) bool {
e, ok := err.(*MultipleError)
if !ok {
return false
}
if len(e.Errors) != 1 {
return false
}
return e.Errors[0].Error() == "failing"
},
},
{
name: "ModeFailOverToOriginalValue_custom_unmarshal_failing",
input: map[string]interface{}{"field": ""},
v: &failingCustomUnmarshalerParent{},
mode: ModeFailOverToOriginalValue,
result: true,
errValidator: func(err error) bool {
e, ok := err.(*MultipleError)
if !ok {
return false
}
if len(e.Errors) != 1 {
return false
}
return e.Errors[0].Error() == "failing"
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := UnmarshalFromJSONMap(tt.input, tt.v, WithMode(tt.mode))
if !tt.errValidator(err) {
t.Errorf("Unmarshal() unexpected error = %v", err)
return
}
if tt.result {
if got == nil {
t.Error("Unmarshal() expected result exists")
return
}
} else {
if got != nil {
t.Error("Unmarshal() expected result not exists")
return
}
}
})
}
}
func TestUnmarshalFromJSONMapEmbedding(t *testing.T) {
t.Run("test_embedded_values", func(t *testing.T) {
p := embeddingParent{}
result, err := UnmarshalFromJSONMap(map[string]interface{}{"field": "value"}, &p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if p.Field != "value" {
t.Errorf("missing embedded value in struct %+v", p)
}
if len(result) != 1 || result["field"] != "value" {
t.Errorf("missing embedded value in map %+v", result)
}
})
}
func TestUnmarshalFromJSONMapJSONDataHandler(t *testing.T) {
t.Run("test_JSONDataHandler", func(t *testing.T) {
data := map[string]interface{}{
"known": "foo",
"unknown": "boo",
"nested1": map[string]interface{}{
"known": "goo",
"unknown": "doo",
},
"nested2": map[string]interface{}{
"known": "goo",
"unknown": "doo",
},
}
p := &handleJSONDataParent{}
result, err := UnmarshalFromJSONMap(data, p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
_, ok := result["nested1"].(handleJSONDataChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested1.Data == nil {
t.Error("HandleJSONData not called")
}
if len(p.Nested1.Data) != 2 || p.Nested1.Data["known"] != "goo" || p.Nested1.Data["unknown"] != "doo" {
t.Error("invalid JSON data")
}
_, ok = result["nested2"].(handleJSONDataChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested2.Data == nil {
t.Error("HandleJSONData not called")
}
if len(p.Nested2.Data) != 2 || p.Nested2.Data["known"] != "goo" || p.Nested2.Data["unknown"] != "doo" {
t.Error("invalid JSON data")
}
})
t.Run("test_JSONDataHandler_single_error", func(t *testing.T) {
data := map[string]interface{}{
"known": "foo",
"unknown": "boo",
"nested1": map[string]interface{}{"known": "goo", "unknown": "doo", "fail": true},
"nested2": map[string]interface{}{"known": "goo", "unknown": "doo", "fail": true},
}
p := &handleJSONDataParent{}
_, err := UnmarshalFromJSONMap(data, p)
if err == nil {
t.Errorf("expected JSONDataHandler error %v", err)
}
if err.Error() != "HandleJSONData failure" {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
})
t.Run("test_JSONDataHandler_multiple_error", func(t *testing.T) {
data := map[string]interface{}{
"known": "foo",
"unknown": "boo",
"nested1": map[string]interface{}{"known": "goo", "unknown": "doo", "fail": true},
"nested2": map[string]interface{}{"known": "goo", "unknown": "doo", "fail": true},
}
p := &handleJSONDataParent{}
_, err := UnmarshalFromJSONMap(data, p, WithMode(ModeAllowMultipleErrors))
if err == nil {
t.Errorf("expected JSONDataHandler error %v", err)
}
e, ok := err.(*MultipleError)
if !ok {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
for _, currentError := range e.Errors {
if currentError.Error() != "HandleJSONData failure" {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
}
})
t.Run("test_JSONDataHandler_deprecated", func(t *testing.T) {
data := map[string]interface{}{
"known": "foo",
"unknown": "boo",
"nested": map[string]interface{}{
"known": "goo",
"unknown": "doo",
},
}
p := &handleJSONDataDeprecatedParent{}
result, err := UnmarshalFromJSONMap(data, p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
_, ok := result["nested"].(handleJSONDataDeprecatedChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested.Data == nil {
t.Error("HandleJSONData not called")
}
if len(p.Nested.Data) != 2 || p.Nested.Data["known"] != "goo" || p.Nested.Data["unknown"] != "doo" {
t.Error("invalid JSON data")
}
})
}
func TestUnmarshalFromJSONMapExcludeKnownFieldsFromMap(t *testing.T) {
t.Run("test_exclude_known_fields_from_map_with_empty_map", func(t *testing.T) {
p := Person{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{
"firstName": "string_firstName",
"lastName": "string_LastName",
},
&p,
WithExcludeKnownFieldsFromMap(true),
)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(result) != 0 {
t.Errorf("failure in excluding untyped fields")
}
})
t.Run("test_exclude_known_fields_from_map", func(t *testing.T) {
p := Person{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{
"firstName": "string_firstName",
"lastName": "string_LastName",
"unknown": "string_unknown",
},
&p,
WithExcludeKnownFieldsFromMap(true),
)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(result) != 1 {
t.Errorf("failure in excluding fields")
}
_, exists := result["unknown"]
if !exists {
t.Errorf("unknown field is missing in the result")
}
})
}
func TestUnmarshalFromJSONMapNestedSkipPopulate(t *testing.T) {
t.Run("TestUnmarshalFromJSONMapNestedSkipPopulate", func(t *testing.T) {
p := &nestedSkipPopulateParent{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{"child": map[string]interface{}{"foo": "value"}},
p,
WithSkipPopulateStruct(true),
)
if err != nil {
t.Errorf("unexpected error %v", err)
}
value, exists := result["child"]
if !exists {
t.Error("missing child element in result map")
}
child, ok := value.(nestedSkipPopulateChild)
if !ok {
t.Errorf("invalid child type %T in result map", child)
}
if child.Foo != "value" {
t.Errorf("invalid value '%s' in child", child.Foo)
}
})
t.Run("TestUnmarshalFromJSONMapNestedSkipPopulate_with_ModeFailOverToOriginalValue", func(t *testing.T) {
p := &nestedSkipPopulateParent{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{"child": map[string]interface{}{"foo": float64(12)}},
p,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
value, exists := result["child"]
if !exists {
t.Error("missing child element in result map")
}
child, ok := value.(map[string]interface{})
if !ok {
t.Errorf("invalid child type %T in result map", child)
}
if child["foo"] != float64(12) {
t.Errorf("invalid value '%v' in child", child["foo"])
}
})
t.Run("TestUnmarshalFromJSONMapNestedSkipPopulate_all_fields_exist_in_root_struct", func(t *testing.T) {
s := &failOverStruct{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{"a": "a_val", "b": float64(12), "c": "c_val"},
s,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
if result["a"] != "a_val" {
t.Errorf("invalid value '%v' in a", result["a"])
}
if result["b"] != float64(12) {
t.Errorf("invalid value '%v' in a", result["b"])
}
if result["c"] != "c_val" {
t.Errorf("invalid value '%v' in a", result["c"])
}
})
t.Run("TestUnmarshalFromJSONMapNestedSkipPopulate_all_fields_exist_in_nested_struct", func(t *testing.T) {
s := &failOverParent{}
result, err := UnmarshalFromJSONMap(
map[string]interface{}{"child": map[string]interface{}{"a": "a_val", "b": float64(12), "c": "c_val"}},
s,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
val, ok := result["child"]
if !ok {
t.Error("missing child in result value")
}
child, ok := val.(map[string]interface{})
if !ok {
t.Error("invalid child type in result value")
}
if child["a"] != "a_val" {
t.Errorf("invalid value '%v' in a", child["a"])
}
if child["b"] != float64(12) {
t.Errorf("invalid value '%v' in a", child["b"])
}
if child["c"] != "c_val" {
t.Errorf("invalid value '%v' in a", child["c"])
}
})
}
marshmallow-1.1.5/unmarshal_test.go 0000664 0000000 0000000 00000261772 14450471353 0017451 0 ustar 00root root 0000000 0000000 // Copyright 2022 PerimeterX. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package marshmallow
import (
"encoding/json"
"errors"
"fmt"
"github.com/go-test/deep"
"github.com/mailru/easyjson/jlexer"
"reflect"
"strings"
"testing"
)
func TestUnmarshalInputVariations(t *testing.T) {
EnableCache()
tests := []struct {
name string
mode Mode
expectedErr bool
expectedResult bool
structModifier func(*parentStruct)
inputMapModifier func(map[string]interface{})
expectedMapModifier func(map[string]interface{})
}{
{
name: "ModeFailOnFirstError_happy_flow",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_zero_struct_value",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_null_on_struct",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeFailOnFirstError_null_on_string",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeFailOnFirstError_null_on_slice",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeFailOnFirstError_null_on_array",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeFailOnFirstError_null_on_map",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOnFirstError_invalid_struct_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_ptr_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_ptr_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_primitive_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_struct_ptr_map_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_bool_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int8_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int16_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint8_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint16_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float32_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float64_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_bool_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int8_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int16_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_int64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint8_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint16_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_uint64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float32_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_float64_ptr_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_slice_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_string_array_value",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_slice_element",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_array_element",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: nil,
},
{
name: "ModeFailOnFirstError_invalid_map_entry",
mode: ModeFailOnFirstError,
expectedErr: true,
expectedResult: false,
structModifier: nil,
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_happy_flow",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_zero_struct_value",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeAllowMultipleErrors_null_on_struct",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeAllowMultipleErrors_null_on_string",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeAllowMultipleErrors_null_on_slice",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeAllowMultipleErrors_null_on_array",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeAllowMultipleErrors_null_on_map",
mode: ModeAllowMultipleErrors,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field1")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField2 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field2")
},
},
{
name: "ModeAllowMultipleErrors_invalid_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field3")
},
},
{
name: "ModeAllowMultipleErrors_invalid_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field4")
},
},
{
name: "ModeAllowMultipleErrors_invalid_ptr_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField5 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field5")
},
},
{
name: "ModeAllowMultipleErrors_invalid_ptr_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField6 = [4]*childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field6")
},
},
{
name: "ModeAllowMultipleErrors_invalid_primitive_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field7")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField8 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field8")
},
},
{
name: "ModeAllowMultipleErrors_invalid_struct_ptr_map_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField9 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
delete(m, "parent_field9")
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField1 = ""
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeAllowMultipleErrors_invalid_bool_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField2 = false
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField2 = false
},
},
{
name: "ModeAllowMultipleErrors_invalid_int_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField3 = 0
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField3 = 0
},
},
{
name: "ModeAllowMultipleErrors_invalid_int8_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField4 = int8(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField4 = int8(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int16_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField5 = int16(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField5 = int16(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField6 = int32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField6 = int32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_int64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField7 = int64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField7 = int64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField8 = uint(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField8 = uint(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint8_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField9 = uint8(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField9 = uint8(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint16_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField10 = uint16(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField10 = uint16(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField11 = uint32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField11 = uint32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField12 = uint64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField12 = uint64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_float32_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField13 = float32(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField13 = float32(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_float64_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField14 = float64(0)
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField14 = float64(0)
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField15 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField15 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_bool_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField16 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField16 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField17 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField17 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int8_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField18 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField18 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int16_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField19 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField19 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField20 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField20 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_int64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField21 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField21 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField22 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField22 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint8_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField23 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField23 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint16_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField24 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField24 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField25 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField25 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_uint64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField26 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField26 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_float32_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField27 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField27 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_float64_ptr_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField28 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField28 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_slice_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField30 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_string_array_value",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1.ChildField31 = [4]string{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeAllowMultipleErrors_invalid_slice_element",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_array_element",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = nil
},
},
{
name: "ModeAllowMultipleErrors_invalid_map_entry",
mode: ModeAllowMultipleErrors,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_happy_flow",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: nil,
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOverToOriginalValue_zero_struct_value",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: nil,
expectedMapModifier: nil,
},
{
name: "ModeFailOverToOriginalValue_null_on_struct",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_null_on_string",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField1 = ""
},
},
{
name: "ModeFailOverToOriginalValue_null_on_slice",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField30 = nil
},
},
{
name: "ModeFailOverToOriginalValue_null_on_array",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = nil
},
expectedMapModifier: func(m map[string]interface{}) {
c := m["parent_field1"].(childStruct)
c.ChildField31 = [4]string{}
},
},
{
name: "ModeFailOverToOriginalValue_null_on_map",
mode: ModeFailOverToOriginalValue,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: nil,
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = nil
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField2 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field2"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_ptr_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField5 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field5"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_ptr_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField6 = [4]*childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field6"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_primitive_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField8 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field8"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_struct_ptr_map_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField9 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = 12
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field9"] = float64(12)
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field1"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_bool_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field2"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field3"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int8_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field4"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int16_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field5"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field6"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field7"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field8"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint8_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field9"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint16_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field10"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field11"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field12"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float32_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field13"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float64_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field14"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field15"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_bool_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field16"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field17"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int8_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field18"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int16_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field19"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field20"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_int64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field21"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field22"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint8_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field23"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint16_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field24"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field25"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_uint64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field26"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float32_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field27"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_float64_ptr_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field28"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_slice_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field30"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_string_array_value",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = toMap(m["parent_field1"])
m["parent_field1"].(map[string]interface{})["child_field31"] = map[string]interface{}{"foo": "boo"}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_slice_element",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField3 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field3"] = []interface{}{childStruct{}, "foo", nil, nil}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_array_element",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField4 = [4]childStruct{}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{nil, "foo", nil, nil}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field4"] = []interface{}{childStruct{}, "foo", nil, nil}
},
},
{
name: "ModeFailOverToOriginalValue_invalid_map_entry",
mode: ModeFailOverToOriginalValue,
expectedErr: true,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField7 = nil
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": 12, "boo": "c"}
},
expectedMapModifier: func(m map[string]interface{}) {
m["parent_field7"] = map[string]interface{}{"foo": "a", "goo": float64(12), "boo": "c"}
},
},
{
name: "nested_unknown_fields",
mode: ModeFailOnFirstError,
expectedErr: false,
expectedResult: true,
structModifier: func(p *parentStruct) {
p.ParentField1 = childStruct{
ChildField1: "a",
}
},
inputMapModifier: func(m map[string]interface{}) {
m["parent_field1"] = map[string]interface{}{"child_field1": "a", "foo": "f", "boo": "b"}
},
expectedMapModifier: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expectedStruct := buildParentStruct()
if tt.structModifier != nil {
tt.structModifier(expectedStruct)
}
input := toMap(expectedStruct)
for k, v := range extraData {
input[k] = v
}
if tt.inputMapModifier != nil {
tt.inputMapModifier(input)
}
data, err := json.Marshal(input)
if err != nil {
t.Errorf("could not marshal parent: %v", err)
return
}
actualStruct := &parentStruct{}
actualMap, err := Unmarshal(data, actualStruct, WithMode(tt.mode))
if (err != nil) != tt.expectedErr {
t.Errorf("Unmarshal() error = %v, expectedErr %v", err, tt.expectedErr)
}
if tt.expectedResult {
expectedStruct.ParentField10.CustomField = "UnmarshalJSON called"
expectedStruct.ParentField11.CustomField = "UnmarshalJSON called"
if diff := deep.Equal(actualStruct, expectedStruct); diff != nil {
t.Errorf("Unmarshal() struct mismatch (actual, expected):\n%s", strings.Join(diff, "\n"))
}
expectedMap := make(map[string]interface{})
for k, v := range extraData {
expectedMap[k] = v
}
structValue := reflectStructValue(actualStruct)
for name, refInfo := range mapStructFields(actualStruct) {
field := refInfo.field(structValue)
expectedMap[name] = field.Interface()
}
if tt.expectedMapModifier != nil {
tt.expectedMapModifier(expectedMap)
}
if tt.mode == ModeFailOverToOriginalValue {
normalizeMapTypes(actualMap)
}
if diff := deep.Equal(actualMap, expectedMap); diff != nil {
t.Errorf("Unmarshal() map mismatch (actual, expected):\n%s", strings.Join(diff, "\n"))
}
} else {
if reflect.DeepEqual(actualStruct, expectedStruct) {
t.Error("Unmarshal() expected parsing to break before finished")
}
if actualMap != nil {
t.Errorf("Unmarshal() expected actual map to not exist")
}
}
})
}
}
func TestUnmarshalSpecialInput(t *testing.T) {
tests := []struct {
name string
data []byte
v interface{}
mode Mode
result bool
errValidator func(error) bool
}{
{
name: "invalid_input",
data: []byte(`12`),
v: &parentStruct{},
mode: ModeFailOnFirstError,
result: false,
errValidator: func(err error) bool {
return err == ErrInvalidInput
},
},
{
name: "invalid_value",
data: []byte(`{"field":""}`),
v: "",
mode: ModeFailOnFirstError,
result: false,
errValidator: func(err error) bool {
return err == ErrInvalidValue
},
},
{
name: "null_input",
data: []byte(`null`),
v: &parentStruct{},
mode: ModeFailOnFirstError,
result: true,
errValidator: func(err error) bool {
return err == nil
},
},
{
name: "ModeFailOnFirstError_custom_unmarshal_failing",
data: []byte(`{"field":""}`),
v: &failingCustomUnmarshalerParent{},
mode: ModeFailOnFirstError,
result: false,
errValidator: func(err error) bool {
e, ok := err.(*jlexer.LexerError)
if !ok {
return false
}
return e.Reason == "failing"
},
},
{
name: "ModeAllowMultipleErrors_custom_unmarshal_failing",
data: []byte(`{"field":""}`),
v: &failingCustomUnmarshalerParent{},
mode: ModeAllowMultipleErrors,
result: true,
errValidator: func(err error) bool {
e, ok := err.(*MultipleLexerError)
if !ok {
return false
}
if len(e.Errors) != 1 {
return false
}
return e.Errors[0].Reason == "failing"
},
},
{
name: "ModeFailOverToOriginalValue_custom_unmarshal_failing",
data: []byte(`{"field":""}`),
v: &failingCustomUnmarshalerParent{},
mode: ModeFailOverToOriginalValue,
result: true,
errValidator: func(err error) bool {
e, ok := err.(*MultipleLexerError)
if !ok {
return false
}
if len(e.Errors) != 1 {
return false
}
return e.Errors[0].Reason == "failing"
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Unmarshal(tt.data, tt.v, WithMode(tt.mode))
if !tt.errValidator(err) {
t.Errorf("Unmarshal() unexpected error = %v", err)
return
}
if tt.result {
if got == nil {
t.Error("Unmarshal() expected result exists")
return
}
} else {
if got != nil {
t.Error("Unmarshal() expected result not exists")
return
}
}
})
}
}
type embeddingParent struct {
embeddingChild
}
type embeddingChild struct {
Field string `json:"field"`
}
func TestEmbedding(t *testing.T) {
t.Run("test_embedded_values", func(t *testing.T) {
p := embeddingParent{}
result, err := Unmarshal([]byte(`{"field":"value"}`), &p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
if p.Field != "value" {
t.Errorf("missing embedded value in struct %+v", p)
}
if len(result) != 1 || result["field"] != "value" {
t.Errorf("missing embedded value in map %+v", result)
}
})
}
type handleJSONDataParent struct {
Known string `json:"known"`
Nested1 handleJSONDataChild `json:"nested1"`
Nested2 handleJSONDataChild `json:"nested2"`
}
type handleJSONDataChild struct {
Known string `json:"known"`
Data map[string]interface{} `json:"-"`
}
func (c *handleJSONDataChild) HandleJSONData(data map[string]interface{}) error {
if _, exists := data["fail"]; exists {
return errors.New("HandleJSONData failure")
}
c.Data = data
return nil
}
type handleJSONDataDeprecatedParent struct {
Known string `json:"known"`
Nested handleJSONDataDeprecatedChild `json:"nested"`
}
type handleJSONDataDeprecatedChild struct {
Known string `json:"known"`
Data map[string]interface{} `json:"-"`
}
func (c *handleJSONDataDeprecatedChild) HandleJSONData(data map[string]interface{}) {
c.Data = data
}
func TestJSONDataHandler(t *testing.T) {
t.Run("test_JSONDataHandler", func(t *testing.T) {
data := []byte(`{
"known": "foo",
"unknown":"boo",
"nested1": {"known": "goo","unknown": "doo"},
"nested2": {"known": "goo","unknown": "doo"}
}`)
p := &handleJSONDataParent{}
result, err := Unmarshal(data, p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
_, ok := result["nested1"].(handleJSONDataChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested1.Data == nil {
t.Error("Nested1 HandleJSONData not called")
}
if len(p.Nested1.Data) != 2 || p.Nested1.Data["known"] != "goo" || p.Nested1.Data["unknown"] != "doo" {
t.Error("Nested1 invalid JSON data")
}
_, ok = result["nested2"].(handleJSONDataChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested2.Data == nil {
t.Error("Nested2 HandleJSONData not called")
}
if len(p.Nested2.Data) != 2 || p.Nested2.Data["known"] != "goo" || p.Nested2.Data["unknown"] != "doo" {
t.Error("Nested2 invalid JSON data")
}
})
t.Run("test_JSONDataHandler_single_error", func(t *testing.T) {
data := []byte(`{
"known": "foo",
"unknown":"boo",
"nested1": {"known": "goo","unknown": "doo", "fail": true},
"nested2": {"known": "goo","unknown": "doo", "fail": true}
}`)
p := &handleJSONDataParent{}
_, err := Unmarshal(data, p)
if err == nil {
t.Errorf("expected JSONDataHandler error %v", err)
}
e, ok := err.(*jlexer.LexerError)
if !ok || e.Reason != "HandleJSONData failure" {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
})
t.Run("test_JSONDataHandler_multiple_error", func(t *testing.T) {
data := []byte(`{
"known": "foo",
"unknown":"boo",
"nested1": {"known": "goo","unknown": "doo", "fail": true},
"nested2": {"known": "goo","unknown": "doo", "fail": true}
}`)
p := &handleJSONDataParent{}
_, err := Unmarshal(data, p, WithMode(ModeAllowMultipleErrors))
if err == nil {
t.Errorf("expected JSONDataHandler error %v", err)
}
e, ok := err.(*MultipleLexerError)
if !ok {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
for _, lexerError := range e.Errors {
if lexerError.Reason != "HandleJSONData failure" {
t.Errorf("unexpected JSONDataHandler error type %v", err)
}
}
})
t.Run("test_JSONDataHandler_deprecated", func(t *testing.T) {
data := []byte(`{"known": "foo","unknown": "boo","nested": {"known": "goo","unknown": "doo"}}`)
p := &handleJSONDataDeprecatedParent{}
result, err := Unmarshal(data, p)
if err != nil {
t.Errorf("unexpected error %v", err)
}
_, ok := result["nested"].(handleJSONDataDeprecatedChild)
if !ok {
t.Error("invalid map value")
}
if p.Nested.Data == nil {
t.Error("HandleJSONData not called")
}
if len(p.Nested.Data) != 2 || p.Nested.Data["known"] != "goo" || p.Nested.Data["unknown"] != "doo" {
t.Error("invalid JSON data")
}
})
}
type Person struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
}
func TestExcludeKnownFieldsFromMap(t *testing.T) {
t.Run("test_exclude_known_fields_from_map_with_empty_map", func(t *testing.T) {
p := Person{}
result, err := Unmarshal([]byte(`{"firstName": "string_firstName", "lastName": "string_lastName"}`), &p, WithExcludeKnownFieldsFromMap(true))
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(result) != 0 {
t.Errorf("failure in excluding untyped fields")
}
})
t.Run("test_exclude_known_fields_from_map", func(t *testing.T) {
p := Person{}
result, err := Unmarshal([]byte(`{"firstName": "string_firstName", "lastName": "string_lastName", "unknown":"string_unknown"}`), &p, WithExcludeKnownFieldsFromMap(true))
if err != nil {
t.Errorf("unexpected error %v", err)
}
if len(result) != 1 {
t.Errorf("failure in excluding untyped fields")
}
_, exists := result["unknown"]
if !exists {
t.Errorf("unknown field is missing in the result")
}
})
}
func TestNestedSkipPopulate(t *testing.T) {
t.Run("TestNestedSkipPopulate", func(t *testing.T) {
p := &nestedSkipPopulateParent{}
result, err := Unmarshal([]byte(`{"child":{"foo":"value"}}`), p, WithSkipPopulateStruct(true))
if err != nil {
t.Errorf("unexpected error %v", err)
}
value, exists := result["child"]
if !exists {
t.Error("missing child element in result map")
}
child, ok := value.(nestedSkipPopulateChild)
if !ok {
t.Errorf("invalid child type %T in result map", child)
}
if child.Foo != "value" {
t.Errorf("invalid value '%s' in child", child.Foo)
}
})
t.Run("TestNestedSkipPopulate_with_ModeFailOverToOriginalValue", func(t *testing.T) {
p := &nestedSkipPopulateParent{}
result, err := Unmarshal(
[]byte(`{"child":{"abc":"123","foo":12}}`),
p,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
value, exists := result["child"]
if !exists {
t.Error("missing child element in result map")
}
child, ok := value.(map[string]interface{})
if !ok {
t.Errorf("invalid child type %T in result map", child)
}
if child["foo"] != float64(12) {
t.Errorf("invalid value '%v' in child", child["foo"])
}
})
t.Run("TestNestedSkipPopulate_all_fields_exist_in_root_struct", func(t *testing.T) {
s := &failOverStruct{}
result, err := Unmarshal(
[]byte(`{"a":"a_val","b":12,"c":"c_val"}}`),
s,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
if result["a"] != "a_val" {
t.Errorf("invalid value '%v' in a", result["a"])
}
if result["b"] != float64(12) {
t.Errorf("invalid value '%v' in a", result["b"])
}
if result["c"] != "c_val" {
t.Errorf("invalid value '%v' in a", result["c"])
}
})
t.Run("TestNestedSkipPopulate_all_fields_exist_in_nested_struct", func(t *testing.T) {
s := &failOverParent{}
result, err := Unmarshal(
[]byte(`{"child":{"a":"a_val","b":12,"c":"c_val"}}}`),
s,
WithMode(ModeFailOverToOriginalValue),
WithSkipPopulateStruct(true),
)
if err == nil {
t.Error("expected error")
}
val, ok := result["child"]
if !ok {
t.Error("missing child in result value")
}
child, ok := val.(map[string]interface{})
if !ok {
t.Error("invalid child type in result value")
}
if child["a"] != "a_val" {
t.Errorf("invalid value '%v' in a", child["a"])
}
if child["b"] != float64(12) {
t.Errorf("invalid value '%v' in a", child["b"])
}
if child["c"] != "c_val" {
t.Errorf("invalid value '%v' in a", child["c"])
}
})
}
type nestedSkipPopulateParent struct {
Child nestedSkipPopulateChild `json:"child"`
}
type nestedSkipPopulateChild struct {
Foo string `json:"foo"`
}
func (c *nestedSkipPopulateChild) HandleJSONData(map[string]interface{}) error {
return nil
}
var extraData = map[string]interface{}{
"extra1": "foo",
"extra2": float64(12),
"extra3": true,
"extra4": []interface{}{"1", false},
}
type failOverParent struct {
Child failOverStruct `json:"child"`
}
type failOverStruct struct {
A string `json:"a"`
B string `json:"b"`
C string `json:"c"`
}
func (f *failOverStruct) HandleJSONData(map[string]interface{}) error {
return nil
}
func buildParentStruct() *parentStruct {
return &parentStruct{
ParentField1: *buildChildStruct(),
ParentField2: buildChildStruct(),
ParentField3: []childStruct{*buildChildStruct()},
ParentField4: [4]childStruct{*buildChildStruct()},
ParentField5: []*childStruct{buildChildStruct(), nil},
ParentField6: [4]*childStruct{buildChildStruct()},
ParentField7: map[string]string{"f6-key-1": "f6-value-1", "f6-key-2": "f6-value-2"},
ParentField8: map[string]childStruct{"f7-key-1": *buildChildStruct()},
ParentField9: map[string]*childStruct{"f8-key-1": buildChildStruct()},
ParentField10: customUnmarshaler{CustomField: "ignore this"},
ParentField11: &customUnmarshaler{CustomField: "ignore this too"},
}
}
func buildChildStruct() *childStruct {
f15 := "field15"
f16 := true
f17 := 17
f18 := int8(18)
f19 := int16(19)
f20 := int32(20)
f21 := int64(21)
f22 := uint(22)
f23 := uint8(23)
f24 := uint16(24)
f25 := uint32(25)
f26 := uint64(26)
f27 := float32(27.7)
f28 := 28.8
return &childStruct{
ChildField1: "field1",
ChildField2: true,
ChildField3: 3,
ChildField4: 4,
ChildField5: 5,
ChildField6: 6,
ChildField7: 7,
ChildField8: 8,
ChildField9: 9,
ChildField10: 10,
ChildField11: 11,
ChildField12: 12,
ChildField13: 13.3,
ChildField14: 14.4,
ChildField15: &f15,
ChildField16: &f16,
ChildField17: &f17,
ChildField18: &f18,
ChildField19: &f19,
ChildField20: &f20,
ChildField21: &f21,
ChildField22: &f22,
ChildField23: &f23,
ChildField24: &f24,
ChildField25: &f25,
ChildField26: &f26,
ChildField27: &f27,
ChildField28: &f28,
ChildField29: "interface",
ChildField30: []string{"f30-1", "f30-2"},
ChildField31: [4]string{"f31-1", "f31-2", "f31-3", "f31-4"},
}
}
func toMap(value interface{}) map[string]interface{} {
data, err := json.Marshal(value)
if err != nil {
panic(fmt.Errorf("could not marshal value to map %v", err))
}
result := make(map[string]interface{})
err = json.Unmarshal(data, &result)
if err != nil {
panic(fmt.Errorf("could not unmarshal value to map %v", err))
}
return result
}
type parentStruct struct {
ParentField1 childStruct `json:"parent_field1"`
ParentField2 *childStruct `json:"parent_field2"`
ParentField3 []childStruct `json:"parent_field3"`
ParentField4 [4]childStruct `json:"parent_field4"`
ParentField5 []*childStruct `json:"parent_field5"`
ParentField6 [4]*childStruct `json:"parent_field6"`
ParentField7 map[string]string `json:"parent_field7"`
ParentField8 map[string]childStruct `json:"parent_field8"`
ParentField9 map[string]*childStruct `json:"parent_field9"`
ParentField10 customUnmarshaler `json:"parent_field10"`
ParentField11 *customUnmarshaler `json:"parent_field11"`
}
type childStruct struct {
ChildField1 string `json:"child_field1,omitempty"`
ChildField2 bool `json:"child_field2"`
ChildField3 int `json:"child_field3"`
ChildField4 int8 `json:"child_field4"`
ChildField5 int16 `json:"child_field5"`
ChildField6 int32 `json:"child_field6"`
ChildField7 int64 `json:"child_field7"`
ChildField8 uint `json:"child_field8"`
ChildField9 uint8 `json:"child_field9"`
ChildField10 uint16 `json:"child_field10"`
ChildField11 uint32 `json:"child_field11"`
ChildField12 uint64 `json:"child_field12"`
ChildField13 float32 `json:"child_field13"`
ChildField14 float64 `json:"child_field14"`
ChildField15 *string `json:"child_field15"`
ChildField16 *bool `json:"child_field16"`
ChildField17 *int `json:"child_field17"`
ChildField18 *int8 `json:"child_field18"`
ChildField19 *int16 `json:"child_field19"`
ChildField20 *int32 `json:"child_field20"`
ChildField21 *int64 `json:"child_field21"`
ChildField22 *uint `json:"child_field22"`
ChildField23 *uint8 `json:"child_field23"`
ChildField24 *uint16 `json:"child_field24"`
ChildField25 *uint32 `json:"child_field25"`
ChildField26 *uint64 `json:"child_field26"`
ChildField27 *float32 `json:"child_field27"`
ChildField28 *float64 `json:"child_field28"`
ChildField29 interface{} `json:"child_field29"`
ChildField30 []string `json:"child_field30"`
ChildField31 [4]string `json:"child_field31"`
}
type customUnmarshaler struct {
CustomField string
}
func (c *customUnmarshaler) UnmarshalJSON([]byte) error {
*c = customUnmarshaler{CustomField: "UnmarshalJSON called"}
return nil
}
func (c *customUnmarshaler) UnmarshalJSONFromMap(interface{}) error {
*c = customUnmarshaler{CustomField: "UnmarshalJSON called"}
return nil
}
type failingCustomUnmarshalerParent struct {
Field *failingCustomUnmarshaler `json:"field"`
}
type failingCustomUnmarshaler struct{}
func (c *failingCustomUnmarshaler) UnmarshalJSON([]byte) error {
return errors.New("failing")
}
func (c *failingCustomUnmarshaler) UnmarshalJSONFromMap(interface{}) error {
return errors.New("failing")
}
func normalizeMapTypes(m map[string]interface{}) {
for k, v := range m {
switch actual := v.(type) {
case uint:
m[k] = float64(actual)
case uint8:
m[k] = float64(actual)
case uint16:
m[k] = float64(actual)
case uint32:
m[k] = float64(actual)
case uint64:
m[k] = float64(actual)
case int:
m[k] = float64(actual)
case int8:
m[k] = float64(actual)
case int16:
m[k] = float64(actual)
case int32:
m[k] = float64(actual)
case int64:
m[k] = float64(actual)
case float32:
m[k] = float64(actual)
case []string:
data := make([]interface{}, len(actual))
for i, item := range actual {
data[i] = item
}
m[k] = data
case [4]string:
data := make([]interface{}, len(actual))
for i, item := range actual {
data[i] = item
}
m[k] = data
case map[string]interface{}:
normalizeMapTypes(actual)
}
}
}