diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index f4db800..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,70 +0,0 @@ -# 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 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml deleted file mode 100644 index 0e72a00..0000000 --- a/.github/workflows/dependency-review.yml +++ /dev/null @@ -1,20 +0,0 @@ -# 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 diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 87fe3b6..0000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,25 +0,0 @@ -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 ./... diff --git a/.gitignore b/.gitignore deleted file mode 100644 index cf53c0a..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/.idea - -coverage.out -profile.out diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 92937d0..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,49 +0,0 @@ -# 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/). diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 0f6c45e..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,133 +0,0 @@ - -# 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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a265c9a..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,47 +0,0 @@ -# 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. diff --git a/LICENSE b/LICENSE index 8ffe869..0692ca1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,159 @@ -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. +## creative commons + +# Attribution 4.0 International + +Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +### Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +* __Considerations for licensors:__ Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. [More considerations for licensors](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors). + +* __Considerations for the public:__ By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. [More considerations for the public](http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees). + +## Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +### Section 1 – Definitions. + +a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + +b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + +c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + +d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + +e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + +f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + +g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + +h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License. + +i. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + +j. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + +k. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +### Section 2 – Scope. + +a. ___License grant.___ + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. __Term.__ The term of this Public License is specified in Section 6(a). + + 4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. __Downstream recipients.__ + + A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. ___Other rights.___ + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +### Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +a. ___Attribution.___ + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +### Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + +b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + +c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +### Section 5 – Disclaimer of Warranties and Limitation of Liability. + +a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__ + +b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__ + +c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +### Section 6 – Term and Termination. + +a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + +b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + +c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + +d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +### Section 7 – Other Terms and Conditions. + +a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + +b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +### Section 8 – Interpretation. + +a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + +b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + +c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + +d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +> Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at [creativecommons.org/policies](http://creativecommons.org/policies), Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. +> +> Creative Commons may be contacted at creativecommons.org \ No newline at end of file diff --git a/README.md b/README.md index bfa9036..ee1718a 100644 --- a/README.md +++ b/README.md @@ -1,205 +1,14 @@ -# Marshmallow +# Marshmallow Assets -![Marshmallow Campfire](https://raw.githubusercontent.com/PerimeterX/marshmallow/assets/campfire.png) +Marshmallow assets by [Adva Rom](https://www.linkedin.com/in/adva-rom-7a6738127/) are licensed under a Creative Commons Attribution 4.0 International License.
-[![CodeQL Status](https://img.shields.io/github/actions/workflow/status/perimeterx/marshmallow/codeql.yml?branch=main&logo=github&label=CodeQL)](https://github.com/PerimeterX/marshmallow/actions/workflows/codeql.yml?query=branch%3Amain++) -[![Run Tests](https://img.shields.io/github/actions/workflow/status/perimeterx/marshmallow/go.yml?branch=main&logo=github&label=Run%20Tests)](https://github.com/PerimeterX/marshmallow/actions/workflows/go.yml?query=branch%3Amain) -[![Dependency Review](https://img.shields.io/github/actions/workflow/status/perimeterx/marshmallow/dependency-review.yml?logo=github&label=Dependency%20Review)](https://github.com/PerimeterX/marshmallow/actions/workflows/dependency-review.yml?query=branch%3Amain) -[![Go Report Card](https://goreportcard.com/badge/github.com/perimeterx/marshmallow)](https://goreportcard.com/report/github.com/perimeterx/marshmallow) -![Manual Code Coverage](https://img.shields.io/badge/coverage-92.6%25-green) -[![Go Reference](https://pkg.go.dev/badge/github.com/perimeterx/marshmallow.svg)](https://pkg.go.dev/github.com/perimeterx/marshmallow) -[![Licence](https://img.shields.io/github/license/perimeterx/marshmallow)](LICENSE) -[![Latest Release](https://img.shields.io/github/v/release/perimeterx/marshmallow)](https://github.com/PerimeterX/marshmallow/releases) -![Top Languages](https://img.shields.io/github/languages/top/perimeterx/marshmallow) -[![Issues](https://img.shields.io/github/issues-closed/perimeterx/marshmallow?color=%238250df&logo=github)](https://github.com/PerimeterX/marshmallow/issues) -[![Pull Requests](https://img.shields.io/github/issues-pr-closed-raw/perimeterx/marshmallow?color=%238250df&label=merged%20pull%20requests&logo=github)](https://github.com/PerimeterX/marshmallow/pulls) -[![Commits](https://img.shields.io/github/last-commit/perimeterx/marshmallow)](https://github.com/PerimeterX/marshmallow/commits/main) -[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md) +A copy of the LICENSE is available at `/LICENSE`. -marshmallow-gopher - -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 performance comparison](https://raw.githubusercontent.com/PerimeterX/marshmallow/e45088ca20d4ea5be4143d418d12da63a68d6dfd/performance-chart.svg) - -**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). +## Contribute 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.
+### Original work / attributions -![Marshmallow Logo](https://raw.githubusercontent.com/PerimeterX/marshmallow/assets/marshmallow.png) +The Go gopher eyes were designed by [Renee French](https://reneefrench.blogspot.com/). +Her design is licensed under the Creative Commons 3.0 Attributions license. diff --git a/benchmark_test.go b/benchmark_test.go deleted file mode 100644 index a69239f..0000000 --- a/benchmark_test.go +++ /dev/null @@ -1,225 +0,0 @@ -// 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"` -} diff --git a/cache.go b/cache.go deleted file mode 100644 index a67cea6..0000000 --- a/cache.go +++ /dev/null @@ -1,63 +0,0 @@ -// 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) -} diff --git a/campfire.png b/campfire.png new file mode 100644 index 0000000..4e1f721 Binary files /dev/null and b/campfire.png differ diff --git a/doc.go b/doc.go deleted file mode 100644 index c179e65..0000000 --- a/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -/* -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 diff --git a/errors.go b/errors.go deleted file mode 100644 index c4d341c..0000000 --- a/errors.go +++ /dev/null @@ -1,101 +0,0 @@ -// 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" -} diff --git a/example_test.go b/example_test.go deleted file mode 100644 index 8741988..0000000 --- a/example_test.go +++ /dev/null @@ -1,254 +0,0 @@ -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 -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 6a80ba2..0000000 --- a/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -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 diff --git a/go.sum b/go.sum deleted file mode 100644 index 2b41360..0000000 --- a/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -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= diff --git a/gopher.png b/gopher.png new file mode 100644 index 0000000..421e122 Binary files /dev/null and b/gopher.png differ diff --git a/marshmallow.png b/marshmallow.png new file mode 100644 index 0000000..79131dd Binary files /dev/null and b/marshmallow.png differ diff --git a/options.go b/options.go deleted file mode 100644 index ff97d33..0000000 --- a/options.go +++ /dev/null @@ -1,96 +0,0 @@ -// 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 -} diff --git a/performance-chart.svg b/performance-chart.svg new file mode 100644 index 0000000..f600ab7 --- /dev/null +++ b/performance-chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/reflection.go b/reflection.go deleted file mode 100644 index 9b7d88c..0000000 --- a/reflection.go +++ /dev/null @@ -1,197 +0,0 @@ -// 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) -} diff --git a/sticker1.png b/sticker1.png new file mode 100644 index 0000000..ac37374 Binary files /dev/null and b/sticker1.png differ diff --git a/sticker2.png b/sticker2.png new file mode 100644 index 0000000..f910f3c Binary files /dev/null and b/sticker2.png differ diff --git a/sticker3.png b/sticker3.png new file mode 100644 index 0000000..8783564 Binary files /dev/null and b/sticker3.png differ diff --git a/sticker4.png b/sticker4.png new file mode 100644 index 0000000..96fb930 Binary files /dev/null and b/sticker4.png differ diff --git a/sticker5.png b/sticker5.png new file mode 100644 index 0000000..319ceb1 Binary files /dev/null and b/sticker5.png differ diff --git a/sticker6.png b/sticker6.png new file mode 100644 index 0000000..8b5f7a1 Binary files /dev/null and b/sticker6.png differ diff --git a/sticker7.png b/sticker7.png new file mode 100644 index 0000000..6b57112 Binary files /dev/null and b/sticker7.png differ diff --git a/sticker8.png b/sticker8.png new file mode 100644 index 0000000..2c5efdc Binary files /dev/null and b/sticker8.png differ diff --git a/unmarshal.go b/unmarshal.go deleted file mode 100644 index 160ea30..0000000 --- a/unmarshal.go +++ /dev/null @@ -1,383 +0,0 @@ -// 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('}') -} diff --git a/unmarshal_from_json_map.go b/unmarshal_from_json_map.go deleted file mode 100644 index 0907f8f..0000000 --- a/unmarshal_from_json_map.go +++ /dev/null @@ -1,295 +0,0 @@ -// 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) - } -} diff --git a/unmarshal_from_json_map_test.go b/unmarshal_from_json_map_test.go deleted file mode 100644 index 366ff31..0000000 --- a/unmarshal_from_json_map_test.go +++ /dev/null @@ -1,2522 +0,0 @@ -// 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"]) - } - }) -} diff --git a/unmarshal_test.go b/unmarshal_test.go deleted file mode 100644 index c579e34..0000000 --- a/unmarshal_test.go +++ /dev/null @@ -1,2793 +0,0 @@ -// 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) - } - } -}