pax_global_header00006660000000000000000000000064145534176720014530gustar00rootroot0000000000000052 comment=01194a0cdbcae43313d5b018bbf184e9325757f2 swag-0.22.8/000077500000000000000000000000001455341767200125625ustar00rootroot00000000000000swag-0.22.8/.editorconfig000066400000000000000000000010331455341767200152340ustar00rootroot00000000000000# top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true indent_style = space indent_size = 2 trim_trailing_whitespace = true # Set default charset [*.{js,py,go,scala,rb,java,html,css,less,sass,md}] charset = utf-8 # Tab indentation (no size specified) [*.go] indent_style = tab [*.md] trim_trailing_whitespace = false # Matches the exact files either package.json or .travis.yml [{package.json,.travis.yml}] indent_style = space indent_size = 2 swag-0.22.8/.gitattributes000066400000000000000000000001131455341767200154500ustar00rootroot00000000000000# gofmt always uses LF, whereas Git uses CRLF on Windows. *.go text eol=lf swag-0.22.8/.github/000077500000000000000000000000001455341767200141225ustar00rootroot00000000000000swag-0.22.8/.github/CONTRIBUTING.md000066400000000000000000000114601455341767200163550ustar00rootroot00000000000000## Contribution Guidelines ### Pull requests are always welcome We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it. If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve. We're trying very hard to keep go-swagger lean and focused. We don't want it to do everything for everybody. This means that we might decide against incorporating a new feature. However, there might be a way to implement that feature *on top of* go-swagger. ### Conventions Fork the repo and make changes on your fork in a feature branch: - If it's a bugfix branch, name it XXX-something where XXX is the number of the issue - If it's a feature branch, create an enhancement issue to announce your intentions, and name it XXX-something where XXX is the number of the issue. Submit unit tests for your changes. Go has a great test framework built in; use it! Take a look at existing tests for inspiration. Run the full test suite on your branch before submitting a pull request. Update the documentation when creating or modifying features. Test your documentation changes for clarity, concision, and correctness, as well as a clean documentation build. See ``docs/README.md`` for more information on building the docs and how docs get released. Write clean code. Universally formatted code promotes ease of writing, reading, and maintenance. Always run `gofmt -s -w file.go` on each changed file before committing your changes. Most editors have plugins that do this automatically. Pull requests descriptions should be as clear as possible and include a reference to all the issues that they address. Pull requests must not contain commits from other users or branches. Commit messages must start with a capitalized and short summary (max. 50 chars) written in the imperative, followed by an optional, more detailed explanatory text which is separated from the summary by an empty line. Code review comments may be added to your pull request. Discuss, then make the suggested modifications and push additional commits to your feature branch. Be sure to post a comment after pushing. The new commits will show up in the pull request automatically, but the reviewers will not be notified unless you comment. Before the pull request is merged, make sure that you squash your commits into logical units of work using `git rebase -i` and `git push -f`. After every commit the test suite should be passing. Include documentation changes in the same commit so that a revert would remove all traces of the feature or fix. Commits that fix or close an issue should include a reference like `Closes #XXX` or `Fixes #XXX`, which will automatically close the issue when merged. ### Sign your work The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify the below (from [developercertificate.org](http://developercertificate.org/)): ``` Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 660 York Street, Suite 102, San Francisco, CA 94110 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. ``` then you just add a line to every git commit message: Signed-off-by: Joe Smith using your real name (sorry, no pseudonyms or anonymous contributions.) You can add the sign off when creating the git commit via `git commit -s`. swag-0.22.8/.github/workflows/000077500000000000000000000000001455341767200161575ustar00rootroot00000000000000swag-0.22.8/.github/workflows/go-test.yml000066400000000000000000000024101455341767200202610ustar00rootroot00000000000000name: go test on: [push, pull_request] jobs: lint: name: Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v4 with: go-version: stable check-latest: true cache: true - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: version: latest only-new-issues: true skip-cache: true test: name: Unit tests runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] go_version: ['oldstable', 'stable' ] steps: - name: Run unit tests uses: actions/setup-go@v4 with: go-version: '${{ matrix.go_version }}' check-latest: true cache: true - uses: actions/checkout@v3 - run: go test -v -race -coverprofile="coverage-${{ matrix.os }}.${{ matrix.go_version }}.out" -covermode=atomic -coverpkg=$(go list)/... ./... - name: Upload coverage to codecov uses: codecov/codecov-action@v3 with: files: './coverage-${{ matrix.os }}.${{ matrix.go_version }}.out' flags: '${{ matrix.go_version }}' os: '${{ matrix.os }}' fail_ci_if_error: false verbose: true swag-0.22.8/.gitignore000066400000000000000000000000461455341767200145520ustar00rootroot00000000000000secrets.yml vendor Godeps .idea *.out swag-0.22.8/.golangci.yml000066400000000000000000000016521455341767200151520ustar00rootroot00000000000000linters-settings: govet: check-shadowing: true golint: min-confidence: 0 gocyclo: min-complexity: 45 maligned: suggest-new: true dupl: threshold: 200 goconst: min-len: 3 min-occurrences: 3 linters: enable-all: true disable: - maligned - lll - gochecknoinits - gochecknoglobals - funlen - godox - gocognit - whitespace - wsl - wrapcheck - testpackage - nlreturn - gomnd - exhaustivestruct - goerr113 - errorlint - nestif - godot - gofumpt - paralleltest - tparallel - thelper - ifshort - exhaustruct - varnamelen - gci - depguard - errchkjson - inamedparam - nonamedreturns - musttag - ireturn - forcetypeassert - cyclop # deprecated linters - deadcode - interfacer - scopelint - varcheck - structcheck - golint - nosnakecase swag-0.22.8/BENCHMARK.md000066400000000000000000000044741455341767200144070ustar00rootroot00000000000000# Benchmarks ## Name mangling utilities ```bash go test -bench XXX -run XXX -benchtime 30s ``` ### Benchmarks at b3e7a5386f996177e4808f11acb2aa93a0f660df ``` goos: linux goarch: amd64 pkg: github.com/go-openapi/swag cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz BenchmarkToXXXName/ToGoName-4 862623 44101 ns/op 10450 B/op 732 allocs/op BenchmarkToXXXName/ToVarName-4 853656 40728 ns/op 10468 B/op 734 allocs/op BenchmarkToXXXName/ToFileName-4 1268312 27813 ns/op 9785 B/op 617 allocs/op BenchmarkToXXXName/ToCommandName-4 1276322 27903 ns/op 9785 B/op 617 allocs/op BenchmarkToXXXName/ToHumanNameLower-4 895334 40354 ns/op 10472 B/op 731 allocs/op BenchmarkToXXXName/ToHumanNameTitle-4 882441 40678 ns/op 10566 B/op 749 allocs/op ``` ### Benchmarks after PR #79 ~ x10 performance improvement and ~ /100 memory allocations. ``` goos: linux goarch: amd64 pkg: github.com/go-openapi/swag cpu: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz BenchmarkToXXXName/ToGoName-4 9595830 3991 ns/op 42 B/op 5 allocs/op BenchmarkToXXXName/ToVarName-4 9194276 3984 ns/op 62 B/op 7 allocs/op BenchmarkToXXXName/ToFileName-4 17002711 2123 ns/op 147 B/op 7 allocs/op BenchmarkToXXXName/ToCommandName-4 16772926 2111 ns/op 147 B/op 7 allocs/op BenchmarkToXXXName/ToHumanNameLower-4 9788331 3749 ns/op 92 B/op 6 allocs/op BenchmarkToXXXName/ToHumanNameTitle-4 9188260 3941 ns/op 104 B/op 6 allocs/op ``` ``` goos: linux goarch: amd64 pkg: github.com/go-openapi/swag cpu: AMD Ryzen 7 5800X 8-Core Processor BenchmarkToXXXName/ToGoName-16 18527378 1972 ns/op 42 B/op 5 allocs/op BenchmarkToXXXName/ToVarName-16 15552692 2093 ns/op 62 B/op 7 allocs/op BenchmarkToXXXName/ToFileName-16 32161176 1117 ns/op 147 B/op 7 allocs/op BenchmarkToXXXName/ToCommandName-16 32256634 1137 ns/op 147 B/op 7 allocs/op BenchmarkToXXXName/ToHumanNameLower-16 18599661 1946 ns/op 92 B/op 6 allocs/op BenchmarkToXXXName/ToHumanNameTitle-16 17581353 2054 ns/op 105 B/op 6 allocs/op ``` swag-0.22.8/CODE_OF_CONDUCT.md000066400000000000000000000062411455341767200153640ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers 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, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ivan+abuse@flanders.co.nz. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ swag-0.22.8/LICENSE000066400000000000000000000261361455341767200135770ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. swag-0.22.8/README.md000066400000000000000000000023561455341767200140470ustar00rootroot00000000000000# Swag [![Build Status](https://github.com/go-openapi/swag/actions/workflows/go-test.yml/badge.svg)](https://github.com/go-openapi/swag/actions?query=workflow%3A"go+test") [![codecov](https://codecov.io/gh/go-openapi/swag/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/swag) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io) [![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/swag/master/LICENSE) [![Go Reference](https://pkg.go.dev/badge/github.com/go-openapi/swag.svg)](https://pkg.go.dev/github.com/go-openapi/swag) [![Go Report Card](https://goreportcard.com/badge/github.com/go-openapi/swag)](https://goreportcard.com/report/github.com/go-openapi/swag) Contains a bunch of helper functions for go-openapi and go-swagger projects. You may also use it standalone for your projects. * convert between value and pointers for builtin types * convert from string to builtin types (wraps strconv) * fast json concatenation * search in path * load from file or http * name mangling This repo has only few dependencies outside of the standard library: * YAML utilities depend on `gopkg.in/yaml.v3` * `github.com/mailru/easyjson v0.7.7` swag-0.22.8/convert.go000066400000000000000000000123221455341767200145710ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "math" "strconv" "strings" ) // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER const ( maxJSONFloat = float64(1<<53 - 1) // 9007199254740991.0 2^53 - 1 minJSONFloat = -float64(1<<53 - 1) //-9007199254740991.0 -2^53 - 1 epsilon float64 = 1e-9 ) // IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive func IsFloat64AJSONInteger(f float64) bool { if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat { return false } fa := math.Abs(f) g := float64(uint64(f)) ga := math.Abs(g) diff := math.Abs(f - g) // more info: https://floating-point-gui.de/errors/comparison/#look-out-for-edge-cases switch { case f == g: // best case return true case f == float64(int64(f)) || f == float64(uint64(f)): // optimistic case return true case f == 0 || g == 0 || diff < math.SmallestNonzeroFloat64: // very close to 0 values return diff < (epsilon * math.SmallestNonzeroFloat64) } // check the relative error return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon } var evaluatesAsTrue map[string]struct{} func init() { evaluatesAsTrue = map[string]struct{}{ "true": {}, "1": {}, "yes": {}, "ok": {}, "y": {}, "on": {}, "selected": {}, "checked": {}, "t": {}, "enabled": {}, } } // ConvertBool turn a string into a boolean func ConvertBool(str string) (bool, error) { _, ok := evaluatesAsTrue[strings.ToLower(str)] return ok, nil } // ConvertFloat32 turn a string into a float32 func ConvertFloat32(str string) (float32, error) { f, err := strconv.ParseFloat(str, 32) if err != nil { return 0, err } return float32(f), nil } // ConvertFloat64 turn a string into a float64 func ConvertFloat64(str string) (float64, error) { return strconv.ParseFloat(str, 64) } // ConvertInt8 turn a string into an int8 func ConvertInt8(str string) (int8, error) { i, err := strconv.ParseInt(str, 10, 8) if err != nil { return 0, err } return int8(i), nil } // ConvertInt16 turn a string into an int16 func ConvertInt16(str string) (int16, error) { i, err := strconv.ParseInt(str, 10, 16) if err != nil { return 0, err } return int16(i), nil } // ConvertInt32 turn a string into an int32 func ConvertInt32(str string) (int32, error) { i, err := strconv.ParseInt(str, 10, 32) if err != nil { return 0, err } return int32(i), nil } // ConvertInt64 turn a string into an int64 func ConvertInt64(str string) (int64, error) { return strconv.ParseInt(str, 10, 64) } // ConvertUint8 turn a string into an uint8 func ConvertUint8(str string) (uint8, error) { i, err := strconv.ParseUint(str, 10, 8) if err != nil { return 0, err } return uint8(i), nil } // ConvertUint16 turn a string into an uint16 func ConvertUint16(str string) (uint16, error) { i, err := strconv.ParseUint(str, 10, 16) if err != nil { return 0, err } return uint16(i), nil } // ConvertUint32 turn a string into an uint32 func ConvertUint32(str string) (uint32, error) { i, err := strconv.ParseUint(str, 10, 32) if err != nil { return 0, err } return uint32(i), nil } // ConvertUint64 turn a string into an uint64 func ConvertUint64(str string) (uint64, error) { return strconv.ParseUint(str, 10, 64) } // FormatBool turns a boolean into a string func FormatBool(value bool) string { return strconv.FormatBool(value) } // FormatFloat32 turns a float32 into a string func FormatFloat32(value float32) string { return strconv.FormatFloat(float64(value), 'f', -1, 32) } // FormatFloat64 turns a float64 into a string func FormatFloat64(value float64) string { return strconv.FormatFloat(value, 'f', -1, 64) } // FormatInt8 turns an int8 into a string func FormatInt8(value int8) string { return strconv.FormatInt(int64(value), 10) } // FormatInt16 turns an int16 into a string func FormatInt16(value int16) string { return strconv.FormatInt(int64(value), 10) } // FormatInt32 turns an int32 into a string func FormatInt32(value int32) string { return strconv.Itoa(int(value)) } // FormatInt64 turns an int64 into a string func FormatInt64(value int64) string { return strconv.FormatInt(value, 10) } // FormatUint8 turns an uint8 into a string func FormatUint8(value uint8) string { return strconv.FormatUint(uint64(value), 10) } // FormatUint16 turns an uint16 into a string func FormatUint16(value uint16) string { return strconv.FormatUint(uint64(value), 10) } // FormatUint32 turns an uint32 into a string func FormatUint32(value uint32) string { return strconv.FormatUint(uint64(value), 10) } // FormatUint64 turns an uint64 into a string func FormatUint64(value uint64) string { return strconv.FormatUint(value, 10) } swag-0.22.8/convert_test.go000066400000000000000000000146011455341767200156320ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "math" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func errMsg(f string) string { const ( expectedQuote = "expected '" errSuffix = "' to generate an error" ) return expectedQuote + f + errSuffix } // These are really dumb tests func TestConvertBool(t *testing.T) { for k := range evaluatesAsTrue { r, err := ConvertBool(k) require.NoError(t, err) assert.True(t, r) } for _, k := range []string{"a", "", "0", "false", "unchecked"} { r, err := ConvertBool(k) require.NoError(t, err) assert.False(t, r) } } func TestConvertFloat32(t *testing.T) { validFloats := []float32{1.0, -1, math.MaxFloat32, math.SmallestNonzeroFloat32, 0, 5.494430303} invalidFloats := []string{"a", strconv.FormatFloat(math.MaxFloat64, 'f', -1, 64), "true"} for _, f := range validFloats { c, err := ConvertFloat32(FormatFloat32(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidFloats { _, err := ConvertFloat32(f) require.Error(t, err, errMsg(f)) } } func TestConvertFloat64(t *testing.T) { validFloats := []float64{1.0, -1, float64(math.MaxFloat32), float64(math.SmallestNonzeroFloat32), math.MaxFloat64, math.SmallestNonzeroFloat64, 0, 5.494430303} invalidFloats := []string{"a", "true"} for _, f := range validFloats { c, err := ConvertFloat64(FormatFloat64(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidFloats { _, err := ConvertFloat64(f) require.Error(t, err, errMsg(f)) } } func TestConvertInt8(t *testing.T) { validInts := []int8{0, 1, -1, math.MaxInt8, math.MinInt8} invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} for _, f := range validInts { c, err := ConvertInt8(FormatInt8(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidInts { _, err := ConvertInt8(f) require.Error(t, err, errMsg(f)) } } func TestConvertInt16(t *testing.T) { validInts := []int16{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16} invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} for _, f := range validInts { c, err := ConvertInt16(FormatInt16(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidInts { _, err := ConvertInt16(f) require.Error(t, err, errMsg(f)) } } func TestConvertInt32(t *testing.T) { validInts := []int32{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32} invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} for _, f := range validInts { c, err := ConvertInt32(FormatInt32(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidInts { _, err := ConvertInt32(f) require.Error(t, err, errMsg(f)) } } func TestConvertInt64(t *testing.T) { validInts := []int64{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32, math.MaxInt64, math.MinInt64} invalidInts := []string{"1.233", "a", "false"} for _, f := range validInts { c, err := ConvertInt64(FormatInt64(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidInts { _, err := ConvertInt64(f) require.Error(t, err, errMsg(f)) } } func TestConvertUint8(t *testing.T) { validInts := []uint8{0, 1, math.MaxUint8} invalidInts := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} for _, f := range validInts { c, err := ConvertUint8(FormatUint8(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidInts { _, err := ConvertUint8(f) require.Error(t, err, errMsg(f)) } } func TestConvertUint16(t *testing.T) { validUints := []uint16{0, 1, math.MaxUint8, math.MaxUint16} invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} for _, f := range validUints { c, err := ConvertUint16(FormatUint16(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidUints { _, err := ConvertUint16(f) require.Error(t, err, errMsg(f)) } } func TestConvertUint32(t *testing.T) { validUints := []uint32{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32} invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} for _, f := range validUints { c, err := ConvertUint32(FormatUint32(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidUints { _, err := ConvertUint32(f) require.Error(t, err, errMsg(f)) } } func TestConvertUint64(t *testing.T) { validUints := []uint64{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64} invalidUints := []string{"1.233", "a", "false"} for _, f := range validUints { c, err := ConvertUint64(FormatUint64(f)) require.NoError(t, err) assert.EqualValues(t, f, c) } for _, f := range invalidUints { _, err := ConvertUint64(f) require.Error(t, err, errMsg(f)) } } func TestIsFloat64AJSONInteger(t *testing.T) { assert.False(t, IsFloat64AJSONInteger(math.Inf(1))) assert.False(t, IsFloat64AJSONInteger(maxJSONFloat+1)) assert.False(t, IsFloat64AJSONInteger(minJSONFloat-1)) assert.True(t, IsFloat64AJSONInteger(1.0)) assert.True(t, IsFloat64AJSONInteger(maxJSONFloat)) assert.True(t, IsFloat64AJSONInteger(minJSONFloat)) assert.True(t, IsFloat64AJSONInteger(1/0.01*67.15000001)) assert.False(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64)) assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/2)) assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/3)) assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/4)) } func TestFormatBool(t *testing.T) { assert.Equal(t, "true", FormatBool(true)) assert.Equal(t, "false", FormatBool(false)) } swag-0.22.8/convert_types.go000066400000000000000000000365231455341767200160260ustar00rootroot00000000000000package swag import "time" // This file was taken from the aws go sdk // String returns a pointer to of the string value passed in. func String(v string) *string { return &v } // StringValue returns the value of the string pointer passed in or // "" if the pointer is nil. func StringValue(v *string) string { if v != nil { return *v } return "" } // StringSlice converts a slice of string values into a slice of // string pointers func StringSlice(src []string) []*string { dst := make([]*string, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // StringValueSlice converts a slice of string pointers into a slice of // string values func StringValueSlice(src []*string) []string { dst := make([]string, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // StringMap converts a string map of string values into a string // map of string pointers func StringMap(src map[string]string) map[string]*string { dst := make(map[string]*string) for k, val := range src { v := val dst[k] = &v } return dst } // StringValueMap converts a string map of string pointers into a string // map of string values func StringValueMap(src map[string]*string) map[string]string { dst := make(map[string]string) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Bool returns a pointer to of the bool value passed in. func Bool(v bool) *bool { return &v } // BoolValue returns the value of the bool pointer passed in or // false if the pointer is nil. func BoolValue(v *bool) bool { if v != nil { return *v } return false } // BoolSlice converts a slice of bool values into a slice of // bool pointers func BoolSlice(src []bool) []*bool { dst := make([]*bool, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // BoolValueSlice converts a slice of bool pointers into a slice of // bool values func BoolValueSlice(src []*bool) []bool { dst := make([]bool, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // BoolMap converts a string map of bool values into a string // map of bool pointers func BoolMap(src map[string]bool) map[string]*bool { dst := make(map[string]*bool) for k, val := range src { v := val dst[k] = &v } return dst } // BoolValueMap converts a string map of bool pointers into a string // map of bool values func BoolValueMap(src map[string]*bool) map[string]bool { dst := make(map[string]bool) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Int returns a pointer to of the int value passed in. func Int(v int) *int { return &v } // IntValue returns the value of the int pointer passed in or // 0 if the pointer is nil. func IntValue(v *int) int { if v != nil { return *v } return 0 } // IntSlice converts a slice of int values into a slice of // int pointers func IntSlice(src []int) []*int { dst := make([]*int, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // IntValueSlice converts a slice of int pointers into a slice of // int values func IntValueSlice(src []*int) []int { dst := make([]int, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // IntMap converts a string map of int values into a string // map of int pointers func IntMap(src map[string]int) map[string]*int { dst := make(map[string]*int) for k, val := range src { v := val dst[k] = &v } return dst } // IntValueMap converts a string map of int pointers into a string // map of int values func IntValueMap(src map[string]*int) map[string]int { dst := make(map[string]int) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Int32 returns a pointer to of the int32 value passed in. func Int32(v int32) *int32 { return &v } // Int32Value returns the value of the int32 pointer passed in or // 0 if the pointer is nil. func Int32Value(v *int32) int32 { if v != nil { return *v } return 0 } // Int32Slice converts a slice of int32 values into a slice of // int32 pointers func Int32Slice(src []int32) []*int32 { dst := make([]*int32, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Int32ValueSlice converts a slice of int32 pointers into a slice of // int32 values func Int32ValueSlice(src []*int32) []int32 { dst := make([]int32, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Int32Map converts a string map of int32 values into a string // map of int32 pointers func Int32Map(src map[string]int32) map[string]*int32 { dst := make(map[string]*int32) for k, val := range src { v := val dst[k] = &v } return dst } // Int32ValueMap converts a string map of int32 pointers into a string // map of int32 values func Int32ValueMap(src map[string]*int32) map[string]int32 { dst := make(map[string]int32) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Int64 returns a pointer to of the int64 value passed in. func Int64(v int64) *int64 { return &v } // Int64Value returns the value of the int64 pointer passed in or // 0 if the pointer is nil. func Int64Value(v *int64) int64 { if v != nil { return *v } return 0 } // Int64Slice converts a slice of int64 values into a slice of // int64 pointers func Int64Slice(src []int64) []*int64 { dst := make([]*int64, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Int64ValueSlice converts a slice of int64 pointers into a slice of // int64 values func Int64ValueSlice(src []*int64) []int64 { dst := make([]int64, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Int64Map converts a string map of int64 values into a string // map of int64 pointers func Int64Map(src map[string]int64) map[string]*int64 { dst := make(map[string]*int64) for k, val := range src { v := val dst[k] = &v } return dst } // Int64ValueMap converts a string map of int64 pointers into a string // map of int64 values func Int64ValueMap(src map[string]*int64) map[string]int64 { dst := make(map[string]int64) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Uint16 returns a pointer to of the uint16 value passed in. func Uint16(v uint16) *uint16 { return &v } // Uint16Value returns the value of the uint16 pointer passed in or // 0 if the pointer is nil. func Uint16Value(v *uint16) uint16 { if v != nil { return *v } return 0 } // Uint16Slice converts a slice of uint16 values into a slice of // uint16 pointers func Uint16Slice(src []uint16) []*uint16 { dst := make([]*uint16, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Uint16ValueSlice converts a slice of uint16 pointers into a slice of // uint16 values func Uint16ValueSlice(src []*uint16) []uint16 { dst := make([]uint16, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Uint16Map converts a string map of uint16 values into a string // map of uint16 pointers func Uint16Map(src map[string]uint16) map[string]*uint16 { dst := make(map[string]*uint16) for k, val := range src { v := val dst[k] = &v } return dst } // Uint16ValueMap converts a string map of uint16 pointers into a string // map of uint16 values func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { dst := make(map[string]uint16) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Uint returns a pointer to of the uint value passed in. func Uint(v uint) *uint { return &v } // UintValue returns the value of the uint pointer passed in or // 0 if the pointer is nil. func UintValue(v *uint) uint { if v != nil { return *v } return 0 } // UintSlice converts a slice of uint values into a slice of // uint pointers func UintSlice(src []uint) []*uint { dst := make([]*uint, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // UintValueSlice converts a slice of uint pointers into a slice of // uint values func UintValueSlice(src []*uint) []uint { dst := make([]uint, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // UintMap converts a string map of uint values into a string // map of uint pointers func UintMap(src map[string]uint) map[string]*uint { dst := make(map[string]*uint) for k, val := range src { v := val dst[k] = &v } return dst } // UintValueMap converts a string map of uint pointers into a string // map of uint values func UintValueMap(src map[string]*uint) map[string]uint { dst := make(map[string]uint) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Uint32 returns a pointer to of the uint32 value passed in. func Uint32(v uint32) *uint32 { return &v } // Uint32Value returns the value of the uint32 pointer passed in or // 0 if the pointer is nil. func Uint32Value(v *uint32) uint32 { if v != nil { return *v } return 0 } // Uint32Slice converts a slice of uint32 values into a slice of // uint32 pointers func Uint32Slice(src []uint32) []*uint32 { dst := make([]*uint32, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Uint32ValueSlice converts a slice of uint32 pointers into a slice of // uint32 values func Uint32ValueSlice(src []*uint32) []uint32 { dst := make([]uint32, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Uint32Map converts a string map of uint32 values into a string // map of uint32 pointers func Uint32Map(src map[string]uint32) map[string]*uint32 { dst := make(map[string]*uint32) for k, val := range src { v := val dst[k] = &v } return dst } // Uint32ValueMap converts a string map of uint32 pointers into a string // map of uint32 values func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { dst := make(map[string]uint32) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Uint64 returns a pointer to of the uint64 value passed in. func Uint64(v uint64) *uint64 { return &v } // Uint64Value returns the value of the uint64 pointer passed in or // 0 if the pointer is nil. func Uint64Value(v *uint64) uint64 { if v != nil { return *v } return 0 } // Uint64Slice converts a slice of uint64 values into a slice of // uint64 pointers func Uint64Slice(src []uint64) []*uint64 { dst := make([]*uint64, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Uint64ValueSlice converts a slice of uint64 pointers into a slice of // uint64 values func Uint64ValueSlice(src []*uint64) []uint64 { dst := make([]uint64, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Uint64Map converts a string map of uint64 values into a string // map of uint64 pointers func Uint64Map(src map[string]uint64) map[string]*uint64 { dst := make(map[string]*uint64) for k, val := range src { v := val dst[k] = &v } return dst } // Uint64ValueMap converts a string map of uint64 pointers into a string // map of uint64 values func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { dst := make(map[string]uint64) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Float32 returns a pointer to of the float32 value passed in. func Float32(v float32) *float32 { return &v } // Float32Value returns the value of the float32 pointer passed in or // 0 if the pointer is nil. func Float32Value(v *float32) float32 { if v != nil { return *v } return 0 } // Float32Slice converts a slice of float32 values into a slice of // float32 pointers func Float32Slice(src []float32) []*float32 { dst := make([]*float32, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Float32ValueSlice converts a slice of float32 pointers into a slice of // float32 values func Float32ValueSlice(src []*float32) []float32 { dst := make([]float32, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Float32Map converts a string map of float32 values into a string // map of float32 pointers func Float32Map(src map[string]float32) map[string]*float32 { dst := make(map[string]*float32) for k, val := range src { v := val dst[k] = &v } return dst } // Float32ValueMap converts a string map of float32 pointers into a string // map of float32 values func Float32ValueMap(src map[string]*float32) map[string]float32 { dst := make(map[string]float32) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Float64 returns a pointer to of the float64 value passed in. func Float64(v float64) *float64 { return &v } // Float64Value returns the value of the float64 pointer passed in or // 0 if the pointer is nil. func Float64Value(v *float64) float64 { if v != nil { return *v } return 0 } // Float64Slice converts a slice of float64 values into a slice of // float64 pointers func Float64Slice(src []float64) []*float64 { dst := make([]*float64, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // Float64ValueSlice converts a slice of float64 pointers into a slice of // float64 values func Float64ValueSlice(src []*float64) []float64 { dst := make([]float64, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // Float64Map converts a string map of float64 values into a string // map of float64 pointers func Float64Map(src map[string]float64) map[string]*float64 { dst := make(map[string]*float64) for k, val := range src { v := val dst[k] = &v } return dst } // Float64ValueMap converts a string map of float64 pointers into a string // map of float64 values func Float64ValueMap(src map[string]*float64) map[string]float64 { dst := make(map[string]float64) for k, val := range src { if val != nil { dst[k] = *val } } return dst } // Time returns a pointer to of the time.Time value passed in. func Time(v time.Time) *time.Time { return &v } // TimeValue returns the value of the time.Time pointer passed in or // time.Time{} if the pointer is nil. func TimeValue(v *time.Time) time.Time { if v != nil { return *v } return time.Time{} } // TimeSlice converts a slice of time.Time values into a slice of // time.Time pointers func TimeSlice(src []time.Time) []*time.Time { dst := make([]*time.Time, len(src)) for i := 0; i < len(src); i++ { dst[i] = &(src[i]) } return dst } // TimeValueSlice converts a slice of time.Time pointers into a slice of // time.Time values func TimeValueSlice(src []*time.Time) []time.Time { dst := make([]time.Time, len(src)) for i := 0; i < len(src); i++ { if src[i] != nil { dst[i] = *(src[i]) } } return dst } // TimeMap converts a string map of time.Time values into a string // map of time.Time pointers func TimeMap(src map[string]time.Time) map[string]*time.Time { dst := make(map[string]*time.Time) for k, val := range src { v := val dst[k] = &v } return dst } // TimeValueMap converts a string map of time.Time pointers into a string // map of time.Time values func TimeValueMap(src map[string]*time.Time) map[string]time.Time { dst := make(map[string]time.Time) for k, val := range src { if val != nil { dst[k] = *val } } return dst } swag-0.22.8/convert_types_test.go000066400000000000000000000433001455341767200170540ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "reflect" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestStringSlice(t *testing.T) { testCasesStringSlice := [][]string{ {"a", "b", "c", "d", "e"}, {"a", "b", "", "", "e"}, } for idx, in := range testCasesStringSlice { if in == nil { continue } out := StringSlice(in) assertValues(t, in, out, true, idx) out2 := StringValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestStringValueSlice(t *testing.T) { testCasesStringValueSlice := [][]*string{ {String("a"), String("b"), nil, String("c")}, } for idx, in := range testCasesStringValueSlice { if in == nil { continue } out := StringValueSlice(in) assertValues(t, in, out, false, idx) out2 := StringSlice(out) assertValues(t, in, out2, true, idx) } } func TestStringMap(t *testing.T) { testCasesStringMap := []map[string]string{ {"a": "1", "b": "2", "c": "3"}, } for idx, in := range testCasesStringMap { if in == nil { continue } out := StringMap(in) assertValues(t, in, out, true, idx) out2 := StringValueMap(out) assertValues(t, in, out2, false, idx) } } func TestBoolSlice(t *testing.T) { testCasesBoolSlice := [][]bool{ {true, true, false, false}, } for idx, in := range testCasesBoolSlice { if in == nil { continue } out := BoolSlice(in) assertValues(t, in, out, true, idx) out2 := BoolValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestBoolValueSlice(t *testing.T) { testCasesBoolValueSlice := [][]*bool{ {Bool(true), Bool(true), Bool(false), Bool(false)}, } for idx, in := range testCasesBoolValueSlice { if in == nil { continue } out := BoolValueSlice(in) assertValues(t, in, out, false, idx) out2 := BoolSlice(out) assertValues(t, in, out2, true, idx) } } func TestBoolMap(t *testing.T) { testCasesBoolMap := []map[string]bool{ {"a": true, "b": false, "c": true}, } for idx, in := range testCasesBoolMap { if in == nil { continue } out := BoolMap(in) assertValues(t, in, out, true, idx) out2 := BoolValueMap(out) assertValues(t, in, out2, false, idx) } } func TestIntSlice(t *testing.T) { testCasesIntSlice := [][]int{ {1, 2, 3, 4}, } for idx, in := range testCasesIntSlice { if in == nil { continue } out := IntSlice(in) assertValues(t, in, out, true, idx) out2 := IntValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestIntValueSlice(t *testing.T) { testCasesIntValueSlice := [][]*int{ {Int(1), Int(2), Int(3), Int(4)}, } for idx, in := range testCasesIntValueSlice { if in == nil { continue } out := IntValueSlice(in) assertValues(t, in, out, false, idx) out2 := IntSlice(out) assertValues(t, in, out2, true, idx) } } func TestIntMap(t *testing.T) { testCasesIntMap := []map[string]int{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesIntMap { if in == nil { continue } out := IntMap(in) assertValues(t, in, out, true, idx) out2 := IntValueMap(out) assertValues(t, in, out2, false, idx) } } func TestInt64Slice(t *testing.T) { testCasesInt64Slice := [][]int64{ {1, 2, 3, 4}, } for idx, in := range testCasesInt64Slice { if in == nil { continue } out := Int64Slice(in) assertValues(t, in, out, true, idx) out2 := Int64ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestInt64ValueSlice(t *testing.T) { testCasesInt64ValueSlice := [][]*int64{ {Int64(1), Int64(2), Int64(3), Int64(4)}, } for idx, in := range testCasesInt64ValueSlice { if in == nil { continue } out := Int64ValueSlice(in) assertValues(t, in, out, false, idx) out2 := Int64Slice(out) assertValues(t, in, out2, true, idx) } } func TestInt64Map(t *testing.T) { testCasesInt64Map := []map[string]int64{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesInt64Map { if in == nil { continue } out := Int64Map(in) assertValues(t, in, out, true, idx) out2 := Int64ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestFloat32Slice(t *testing.T) { testCasesFloat32Slice := [][]float32{ {1, 2, 3, 4}, } for idx, in := range testCasesFloat32Slice { if in == nil { continue } out := Float32Slice(in) assertValues(t, in, out, true, idx) out2 := Float32ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestFloat64Slice(t *testing.T) { testCasesFloat64Slice := [][]float64{ {1, 2, 3, 4}, } for idx, in := range testCasesFloat64Slice { if in == nil { continue } out := Float64Slice(in) assertValues(t, in, out, true, idx) out2 := Float64ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestUintSlice(t *testing.T) { testCasesUintSlice := [][]uint{ {1, 2, 3, 4}, } for idx, in := range testCasesUintSlice { if in == nil { continue } out := UintSlice(in) assertValues(t, in, out, true, idx) out2 := UintValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestUintValueSlice(t *testing.T) { testCasesUintValueSlice := [][]*uint{} for idx, in := range testCasesUintValueSlice { if in == nil { continue } out := UintValueSlice(in) assertValues(t, in, out, true, idx) out2 := UintSlice(out) assertValues(t, in, out2, false, idx) } } func TestUintMap(t *testing.T) { testCasesUintMap := []map[string]uint{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesUintMap { if in == nil { continue } out := UintMap(in) assertValues(t, in, out, true, idx) out2 := UintValueMap(out) assertValues(t, in, out2, false, idx) } } func TestUint16Slice(t *testing.T) { testCasesUint16Slice := [][]uint16{ {1, 2, 3, 4}, } for idx, in := range testCasesUint16Slice { if in == nil { continue } out := Uint16Slice(in) assertValues(t, in, out, true, idx) out2 := Uint16ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestUint16ValueSlice(t *testing.T) { testCasesUint16ValueSlice := [][]*uint16{} for idx, in := range testCasesUint16ValueSlice { if in == nil { continue } out := Uint16ValueSlice(in) assertValues(t, in, out, true, idx) out2 := Uint16Slice(out) assertValues(t, in, out2, false, idx) } } func TestUint16Map(t *testing.T) { testCasesUint16Map := []map[string]uint16{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesUint16Map { if in == nil { continue } out := Uint16Map(in) assertValues(t, in, out, true, idx) out2 := Uint16ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestUint64Slice(t *testing.T) { testCasesUint64Slice := [][]uint64{ {1, 2, 3, 4}, } for idx, in := range testCasesUint64Slice { if in == nil { continue } out := Uint64Slice(in) assertValues(t, in, out, true, idx) out2 := Uint64ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestUint64ValueSlice(t *testing.T) { testCasesUint64ValueSlice := [][]*uint64{} for idx, in := range testCasesUint64ValueSlice { if in == nil { continue } out := Uint64ValueSlice(in) assertValues(t, in, out, true, idx) out2 := Uint64Slice(out) assertValues(t, in, out2, false, idx) } } func TestUint64Map(t *testing.T) { testCasesUint64Map := []map[string]uint64{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesUint64Map { if in == nil { continue } out := Uint64Map(in) assertValues(t, in, out, true, idx) out2 := Uint64ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestFloat32ValueSlice(t *testing.T) { testCasesFloat32ValueSlice := [][]*float32{} for idx, in := range testCasesFloat32ValueSlice { if in == nil { continue } out := Float32ValueSlice(in) assertValues(t, in, out, true, idx) out2 := Float32Slice(out) assertValues(t, in, out2, false, idx) } } func TestFloat32Map(t *testing.T) { testCasesFloat32Map := []map[string]float32{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesFloat32Map { if in == nil { continue } out := Float32Map(in) assertValues(t, in, out, true, idx) out2 := Float32ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestFloat64ValueSlice(t *testing.T) { testCasesFloat64ValueSlice := [][]*float64{} for idx, in := range testCasesFloat64ValueSlice { if in == nil { continue } out := Float64ValueSlice(in) assertValues(t, in, out, true, idx) out2 := Float64Slice(out) assertValues(t, in, out2, false, idx) } } func TestFloat64Map(t *testing.T) { testCasesFloat64Map := []map[string]float64{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesFloat64Map { if in == nil { continue } out := Float64Map(in) assertValues(t, in, out, true, idx) out2 := Float64ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestTimeSlice(t *testing.T) { testCasesTimeSlice := [][]time.Time{ {time.Now(), time.Now().AddDate(100, 0, 0)}, } for idx, in := range testCasesTimeSlice { if in == nil { continue } out := TimeSlice(in) assertValues(t, in, out, true, idx) out2 := TimeValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestTimeValueSlice(t *testing.T) { testCasesTimeValueSlice := [][]*time.Time{ {Time(time.Now()), Time(time.Now().AddDate(100, 0, 0))}, } for idx, in := range testCasesTimeValueSlice { if in == nil { continue } out := TimeValueSlice(in) assertValues(t, in, out, false, idx) out2 := TimeSlice(out) assertValues(t, in, out2, true, idx) } } func TestTimeMap(t *testing.T) { testCasesTimeMap := []map[string]time.Time{ {"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()}, } for idx, in := range testCasesTimeMap { if in == nil { continue } out := TimeMap(in) assertValues(t, in, out, true, idx) out2 := TimeValueMap(out) assertValues(t, in, out2, false, idx) } } func TestInt32Slice(t *testing.T) { testCasesInt32Slice := [][]int32{ {1, 2, 3, 4}, } for idx, in := range testCasesInt32Slice { if in == nil { continue } out := Int32Slice(in) assertValues(t, in, out, true, idx) out2 := Int32ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestInt32ValueSlice(t *testing.T) { testCasesInt32ValueSlice := [][]*int32{ {Int32(1), Int32(2), Int32(3), Int32(4)}, } for idx, in := range testCasesInt32ValueSlice { if in == nil { continue } out := Int32ValueSlice(in) assertValues(t, in, out, false, idx) out2 := Int32Slice(out) assertValues(t, in, out2, true, idx) } } func TestInt32Map(t *testing.T) { testCasesInt32Map := []map[string]int32{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesInt32Map { if in == nil { continue } out := Int32Map(in) assertValues(t, in, out, true, idx) out2 := Int32ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestUint32Slice(t *testing.T) { testCasesUint32Slice := [][]uint32{ {1, 2, 3, 4}, } for idx, in := range testCasesUint32Slice { if in == nil { continue } out := Uint32Slice(in) assertValues(t, in, out, true, idx) out2 := Uint32ValueSlice(out) assertValues(t, in, out2, false, idx) } } func TestUint32ValueSlice(t *testing.T) { testCasesUint32ValueSlice := [][]*uint32{ {Uint32(1), Uint32(2), Uint32(3), Uint32(4)}, } for idx, in := range testCasesUint32ValueSlice { if in == nil { continue } out := Uint32ValueSlice(in) assertValues(t, in, out, false, idx) out2 := Uint32Slice(out) assertValues(t, in, out2, true, idx) } } func TestUint32Map(t *testing.T) { testCasesUint32Map := []map[string]uint32{ {"a": 3, "b": 2, "c": 1}, } for idx, in := range testCasesUint32Map { if in == nil { continue } out := Uint32Map(in) assertValues(t, in, out, true, idx) out2 := Uint32ValueMap(out) assertValues(t, in, out2, false, idx) } } func TestStringValue(t *testing.T) { testCasesString := []string{"a", "b", "c", "d", "e", ""} for idx, in := range testCasesString { out := String(in) assertValues(t, in, out, true, idx) out2 := StringValue(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, StringValue(nil), "expected conversion from nil to return zero value") } func TestBoolValue(t *testing.T) { testCasesBool := []bool{true, false} for idx, in := range testCasesBool { out := Bool(in) assertValues(t, in, out, true, idx) out2 := BoolValue(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, BoolValue(nil), "expected conversion from nil to return zero value") } func TestIntValue(t *testing.T) { testCasesInt := []int{1, 2, 3, 0} for idx, in := range testCasesInt { out := Int(in) assertValues(t, in, out, true, idx) out2 := IntValue(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, IntValue(nil), "expected conversion from nil to return zero value") } func TestInt32Value(t *testing.T) { testCasesInt32 := []int32{1, 2, 3, 0} for idx, in := range testCasesInt32 { out := Int32(in) assertValues(t, in, out, true, idx) out2 := Int32Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Int32Value(nil), "expected conversion from nil to return zero value") } func TestInt64Value(t *testing.T) { testCasesInt64 := []int64{1, 2, 3, 0} for idx, in := range testCasesInt64 { out := Int64(in) assertValues(t, in, out, true, idx) out2 := Int64Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Int64Value(nil), "expected conversion from nil to return zero value") } func TestUintValue(t *testing.T) { testCasesUint := []uint{1, 2, 3, 0} for idx, in := range testCasesUint { out := Uint(in) assertValues(t, in, out, true, idx) out2 := UintValue(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, UintValue(nil), "expected conversion from nil to return zero value") } func TestUint32Value(t *testing.T) { testCasesUint32 := []uint32{1, 2, 3, 0} for idx, in := range testCasesUint32 { out := Uint32(in) assertValues(t, in, out, true, idx) out2 := Uint32Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Uint32Value(nil), "expected conversion from nil to return zero value") } func TestUint64Value(t *testing.T) { testCasesUint64 := []uint64{1, 2, 3, 0} for idx, in := range testCasesUint64 { out := Uint64(in) assertValues(t, in, out, true, idx) out2 := Uint64Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Uint64Value(nil), "expected conversion from nil to return zero value") } func TestFloat32Value(t *testing.T) { testCasesFloat32 := []float32{1, 2, 3, 0} for idx, in := range testCasesFloat32 { out := Float32(in) assertValues(t, in, out, true, idx) out2 := Float32Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Float32Value(nil), "expected conversion from nil to return zero value") } func TestFloat64Value(t *testing.T) { testCasesFloat64 := []float64{1, 2, 3, 0} for idx, in := range testCasesFloat64 { out := Float64(in) assertValues(t, in, out, true, idx) out2 := Float64Value(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, Float64Value(nil), "expected conversion from nil to return zero value") } func TestTimeValue(t *testing.T) { testCasesTime := []time.Time{ time.Now().AddDate(-100, 0, 0), time.Now(), } for idx, in := range testCasesTime { out := Time(in) assertValues(t, in, out, true, idx) out2 := TimeValue(out) assertValues(t, in, out2, false, idx) } assert.Zerof(t, TimeValue(nil), "expected conversion from nil to return zero value") } func assertSingleValue(t *testing.T, inElem, elem reflect.Value, expectPointer bool, idx int) { require.Equalf(t, expectPointer, (elem.Kind() == reflect.Ptr), "unexpected expectPointer=%t value type", expectPointer, ) if inElem.Kind() == reflect.Ptr && !inElem.IsNil() { inElem = reflect.Indirect(inElem) } if elem.Kind() == reflect.Ptr && !elem.IsNil() { elem = reflect.Indirect(elem) } require.Truef(t, (elem.Kind() == reflect.Ptr && elem.IsNil()) || IsZero(elem.Interface()) == (inElem.Kind() == reflect.Ptr && inElem.IsNil()) || IsZero(inElem.Interface()), "unexpected nil pointer at idx %d", idx, ) if !((elem.Kind() == reflect.Ptr && elem.IsNil()) || IsZero(elem.Interface())) { require.IsTypef(t, inElem.Interface(), elem.Interface(), "Expected in/out to match types") assert.EqualValuesf(t, inElem.Interface(), elem.Interface(), "Unexpected value at idx %d: %v", idx, elem.Interface()) } } // assertValues checks equivalent representation pointer vs values for single var, slices and maps func assertValues(t *testing.T, in, out interface{}, expectPointer bool, idx int) { vin := reflect.ValueOf(in) vout := reflect.ValueOf(out) switch vin.Kind() { //nolint:exhaustive case reflect.Slice, reflect.Map: require.Equalf(t, vin.Kind(), vout.Kind(), "Unexpected output type at idx %d", idx) require.Equalf(t, vin.Len(), vout.Len(), "Unexpected len at idx %d", idx) var elem, inElem reflect.Value for i := 0; i < vin.Len(); i++ { switch vin.Kind() { //nolint:exhaustive case reflect.Slice: elem = vout.Index(i) inElem = vin.Index(i) case reflect.Map: keys := vin.MapKeys() elem = vout.MapIndex(keys[i]) inElem = vout.MapIndex(keys[i]) default: } assertSingleValue(t, inElem, elem, expectPointer, idx) } default: inElem := vin elem := vout assertSingleValue(t, inElem, elem, expectPointer, idx) } } swag-0.22.8/doc.go000066400000000000000000000020731455341767200136600ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* Package swag contains a bunch of helper functions for go-openapi and go-swagger projects. You may also use it standalone for your projects. - convert between value and pointers for builtin types - convert from string to builtin types (wraps strconv) - fast json concatenation - search in path - load from file or http - name mangling This repo has only few dependencies outside of the standard library: - YAML utilities depend on gopkg.in/yaml.v2 */ package swag swag-0.22.8/file.go000066400000000000000000000016411455341767200140320ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import "mime/multipart" // File represents an uploaded file. type File struct { Data multipart.File Header *multipart.FileHeader } // Read bytes from the file func (f *File) Read(p []byte) (n int, err error) { return f.Data.Read(p) } // Close the file func (f *File) Close() error { return f.Data.Close() } swag-0.22.8/file_test.go000066400000000000000000000007131455341767200150700ustar00rootroot00000000000000package swag import ( "io" "testing" "github.com/stretchr/testify/assert" ) func TestFileImplementsIOReader(t *testing.T) { var file interface{} = &File{} expected := "that File implements io.Reader" assert.Implements(t, new(io.Reader), file, expected) } func TestFileImplementsIOReadCloser(t *testing.T) { var file interface{} = &File{} expected := "that File implements io.ReadCloser" assert.Implements(t, new(io.ReadCloser), file, expected) } swag-0.22.8/go.mod000066400000000000000000000010641455341767200136710ustar00rootroot00000000000000module github.com/go-openapi/swag require ( github.com/mailru/easyjson v0.7.7 github.com/pkg/profile v1.7.0 github.com/stretchr/testify v1.8.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) go 1.19 swag-0.22.8/go.sum000066400000000000000000000065761455341767200137330ustar00rootroot00000000000000github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= swag-0.22.8/initialism_index.go000066400000000000000000000106761455341767200164540ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "sort" "strings" "sync" ) var ( // commonInitialisms are common acronyms that are kept as whole uppercased words. commonInitialisms *indexOfInitialisms // initialisms is a slice of sorted initialisms initialisms []string // a copy of initialisms pre-baked as []rune initialismsRunes [][]rune initialismsUpperCased [][]rune isInitialism func(string) bool maxAllocMatches int ) func init() { // Taken from https://github.com/golang/lint/blob/3390df4df2787994aea98de825b964ac7944b817/lint.go#L732-L769 configuredInitialisms := map[string]bool{ "ACL": true, "API": true, "ASCII": true, "CPU": true, "CSS": true, "DNS": true, "EOF": true, "GUID": true, "HTML": true, "HTTPS": true, "HTTP": true, "ID": true, "IP": true, "IPv4": true, "IPv6": true, "JSON": true, "LHS": true, "OAI": true, "QPS": true, "RAM": true, "RHS": true, "RPC": true, "SLA": true, "SMTP": true, "SQL": true, "SSH": true, "TCP": true, "TLS": true, "TTL": true, "UDP": true, "UI": true, "UID": true, "UUID": true, "URI": true, "URL": true, "UTF8": true, "VM": true, "XML": true, "XMPP": true, "XSRF": true, "XSS": true, } // a thread-safe index of initialisms commonInitialisms = newIndexOfInitialisms().load(configuredInitialisms) initialisms = commonInitialisms.sorted() initialismsRunes = asRunes(initialisms) initialismsUpperCased = asUpperCased(initialisms) maxAllocMatches = maxAllocHeuristic(initialismsRunes) // a test function isInitialism = commonInitialisms.isInitialism } func asRunes(in []string) [][]rune { out := make([][]rune, len(in)) for i, initialism := range in { out[i] = []rune(initialism) } return out } func asUpperCased(in []string) [][]rune { out := make([][]rune, len(in)) for i, initialism := range in { out[i] = []rune(upper(trim(initialism))) } return out } func maxAllocHeuristic(in [][]rune) int { heuristic := make(map[rune]int) for _, initialism := range in { heuristic[initialism[0]]++ } var maxAlloc int for _, val := range heuristic { if val > maxAlloc { maxAlloc = val } } return maxAlloc } // AddInitialisms add additional initialisms func AddInitialisms(words ...string) { for _, word := range words { // commonInitialisms[upper(word)] = true commonInitialisms.add(upper(word)) } // sort again initialisms = commonInitialisms.sorted() initialismsRunes = asRunes(initialisms) initialismsUpperCased = asUpperCased(initialisms) } // indexOfInitialisms is a thread-safe implementation of the sorted index of initialisms. // Since go1.9, this may be implemented with sync.Map. type indexOfInitialisms struct { sortMutex *sync.Mutex index *sync.Map } func newIndexOfInitialisms() *indexOfInitialisms { return &indexOfInitialisms{ sortMutex: new(sync.Mutex), index: new(sync.Map), } } func (m *indexOfInitialisms) load(initial map[string]bool) *indexOfInitialisms { m.sortMutex.Lock() defer m.sortMutex.Unlock() for k, v := range initial { m.index.Store(k, v) } return m } func (m *indexOfInitialisms) isInitialism(key string) bool { _, ok := m.index.Load(key) return ok } func (m *indexOfInitialisms) add(key string) *indexOfInitialisms { m.index.Store(key, true) return m } func (m *indexOfInitialisms) sorted() (result []string) { m.sortMutex.Lock() defer m.sortMutex.Unlock() m.index.Range(func(key, value interface{}) bool { k := key.(string) result = append(result, k) return true }) sort.Sort(sort.Reverse(byInitialism(result))) return } type byInitialism []string func (s byInitialism) Len() int { return len(s) } func (s byInitialism) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byInitialism) Less(i, j int) bool { if len(s[i]) != len(s[j]) { return len(s[i]) < len(s[j]) } return strings.Compare(s[i], s[j]) > 0 } swag-0.22.8/json.go000066400000000000000000000175051455341767200140720ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "bytes" "encoding/json" "log" "reflect" "strings" "sync" "github.com/mailru/easyjson/jlexer" "github.com/mailru/easyjson/jwriter" ) // nullJSON represents a JSON object with null type var nullJSON = []byte("null") // DefaultJSONNameProvider the default cache for types var DefaultJSONNameProvider = NewNameProvider() const comma = byte(',') var closers map[byte]byte func init() { closers = map[byte]byte{ '{': '}', '[': ']', } } type ejMarshaler interface { MarshalEasyJSON(w *jwriter.Writer) } type ejUnmarshaler interface { UnmarshalEasyJSON(w *jlexer.Lexer) } // WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler // so it takes the fastest option available. func WriteJSON(data interface{}) ([]byte, error) { if d, ok := data.(ejMarshaler); ok { jw := new(jwriter.Writer) d.MarshalEasyJSON(jw) return jw.BuildBytes() } if d, ok := data.(json.Marshaler); ok { return d.MarshalJSON() } return json.Marshal(data) } // ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler // so it takes the fastest option available func ReadJSON(data []byte, value interface{}) error { trimmedData := bytes.Trim(data, "\x00") if d, ok := value.(ejUnmarshaler); ok { jl := &jlexer.Lexer{Data: trimmedData} d.UnmarshalEasyJSON(jl) return jl.Error() } if d, ok := value.(json.Unmarshaler); ok { return d.UnmarshalJSON(trimmedData) } return json.Unmarshal(trimmedData, value) } // DynamicJSONToStruct converts an untyped json structure into a struct func DynamicJSONToStruct(data interface{}, target interface{}) error { // TODO: convert straight to a json typed map (mergo + iterate?) b, err := WriteJSON(data) if err != nil { return err } return ReadJSON(b, target) } // ConcatJSON concatenates multiple json objects efficiently func ConcatJSON(blobs ...[]byte) []byte { if len(blobs) == 0 { return nil } last := len(blobs) - 1 for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) { // strips trailing null objects last-- if last < 0 { // there was nothing but "null"s or nil... return nil } } if last == 0 { return blobs[0] } var opening, closing byte var idx, a int buf := bytes.NewBuffer(nil) for i, b := range blobs[:last+1] { if b == nil || bytes.Equal(b, nullJSON) { // a null object is in the list: skip it continue } if len(b) > 0 && opening == 0 { // is this an array or an object? opening, closing = b[0], closers[b[0]] } if opening != '{' && opening != '[' { continue // don't know how to concatenate non container objects } if len(b) < 3 { // yep empty but also the last one, so closing this thing if i == last && a > 0 { if err := buf.WriteByte(closing); err != nil { log.Println(err) } } continue } idx = 0 if a > 0 { // we need to join with a comma for everything beyond the first non-empty item if err := buf.WriteByte(comma); err != nil { log.Println(err) } idx = 1 // this is not the first or the last so we want to drop the leading bracket } if i != last { // not the last one, strip brackets if _, err := buf.Write(b[idx : len(b)-1]); err != nil { log.Println(err) } } else { // last one, strip only the leading bracket if _, err := buf.Write(b[idx:]); err != nil { log.Println(err) } } a++ } // somehow it ended up being empty, so provide a default value if buf.Len() == 0 { if err := buf.WriteByte(opening); err != nil { log.Println(err) } if err := buf.WriteByte(closing); err != nil { log.Println(err) } } return buf.Bytes() } // ToDynamicJSON turns an object into a properly JSON typed structure func ToDynamicJSON(data interface{}) interface{} { // TODO: convert straight to a json typed map (mergo + iterate?) b, err := json.Marshal(data) if err != nil { log.Println(err) } var res interface{} if err := json.Unmarshal(b, &res); err != nil { log.Println(err) } return res } // FromDynamicJSON turns an object into a properly JSON typed structure func FromDynamicJSON(data, target interface{}) error { b, err := json.Marshal(data) if err != nil { log.Println(err) } return json.Unmarshal(b, target) } // NameProvider represents an object capable of translating from go property names // to json property names // This type is thread-safe. type NameProvider struct { lock *sync.Mutex index map[reflect.Type]nameIndex } type nameIndex struct { jsonNames map[string]string goNames map[string]string } // NewNameProvider creates a new name provider func NewNameProvider() *NameProvider { return &NameProvider{ lock: &sync.Mutex{}, index: make(map[reflect.Type]nameIndex), } } func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) { for i := 0; i < tpe.NumField(); i++ { targetDes := tpe.Field(i) if targetDes.PkgPath != "" { // unexported continue } if targetDes.Anonymous { // walk embedded structures tree down first buildnameIndex(targetDes.Type, idx, reverseIdx) continue } if tag := targetDes.Tag.Get("json"); tag != "" { parts := strings.Split(tag, ",") if len(parts) == 0 { continue } nm := parts[0] if nm == "-" { continue } if nm == "" { // empty string means we want to use the Go name nm = targetDes.Name } idx[nm] = targetDes.Name reverseIdx[targetDes.Name] = nm } } } func newNameIndex(tpe reflect.Type) nameIndex { var idx = make(map[string]string, tpe.NumField()) var reverseIdx = make(map[string]string, tpe.NumField()) buildnameIndex(tpe, idx, reverseIdx) return nameIndex{jsonNames: idx, goNames: reverseIdx} } // GetJSONNames gets all the json property names for a type func (n *NameProvider) GetJSONNames(subject interface{}) []string { n.lock.Lock() defer n.lock.Unlock() tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() names, ok := n.index[tpe] if !ok { names = n.makeNameIndex(tpe) } res := make([]string, 0, len(names.jsonNames)) for k := range names.jsonNames { res = append(res, k) } return res } // GetJSONName gets the json name for a go property name func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) { tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() return n.GetJSONNameForType(tpe, name) } // GetJSONNameForType gets the json name for a go property name on a given type func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) { n.lock.Lock() defer n.lock.Unlock() names, ok := n.index[tpe] if !ok { names = n.makeNameIndex(tpe) } nme, ok := names.goNames[name] return nme, ok } func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex { names := newNameIndex(tpe) n.index[tpe] = names return names } // GetGoName gets the go name for a json property name func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) { tpe := reflect.Indirect(reflect.ValueOf(subject)).Type() return n.GetGoNameForType(tpe, name) } // GetGoNameForType gets the go name for a given type for a json property name func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) { n.lock.Lock() defer n.lock.Unlock() names, ok := n.index[tpe] if !ok { names = n.makeNameIndex(tpe) } nme, ok := names.jsonNames[name] return nme, ok } swag-0.22.8/json_test.go000066400000000000000000000175671455341767200151410ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "reflect" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type testNameStruct struct { Name string `json:"name"` NotTheSame int64 `json:"plain"` Ignored string `json:"-"` } func TestNameProvider(t *testing.T) { provider := NewNameProvider() var obj = testNameStruct{} nm, ok := provider.GetGoName(obj, "name") assert.True(t, ok) assert.Equal(t, "Name", nm) nm, ok = provider.GetGoName(obj, "plain") assert.True(t, ok) assert.Equal(t, "NotTheSame", nm) nm, ok = provider.GetGoName(obj, "doesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetGoName(obj, "ignored") assert.False(t, ok) assert.Empty(t, nm) tpe := reflect.TypeOf(obj) nm, ok = provider.GetGoNameForType(tpe, "name") assert.True(t, ok) assert.Equal(t, "Name", nm) nm, ok = provider.GetGoNameForType(tpe, "plain") assert.True(t, ok) assert.Equal(t, "NotTheSame", nm) nm, ok = provider.GetGoNameForType(tpe, "doesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetGoNameForType(tpe, "ignored") assert.False(t, ok) assert.Empty(t, nm) ptr := &obj nm, ok = provider.GetGoName(ptr, "name") assert.True(t, ok) assert.Equal(t, "Name", nm) nm, ok = provider.GetGoName(ptr, "plain") assert.True(t, ok) assert.Equal(t, "NotTheSame", nm) nm, ok = provider.GetGoName(ptr, "doesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetGoName(ptr, "ignored") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONName(obj, "Name") assert.True(t, ok) assert.Equal(t, "name", nm) nm, ok = provider.GetJSONName(obj, "NotTheSame") assert.True(t, ok) assert.Equal(t, "plain", nm) nm, ok = provider.GetJSONName(obj, "DoesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONName(obj, "Ignored") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONNameForType(tpe, "Name") assert.True(t, ok) assert.Equal(t, "name", nm) nm, ok = provider.GetJSONNameForType(tpe, "NotTheSame") assert.True(t, ok) assert.Equal(t, "plain", nm) nm, ok = provider.GetJSONNameForType(tpe, "doesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONNameForType(tpe, "Ignored") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONName(ptr, "Name") assert.True(t, ok) assert.Equal(t, "name", nm) nm, ok = provider.GetJSONName(ptr, "NotTheSame") assert.True(t, ok) assert.Equal(t, "plain", nm) nm, ok = provider.GetJSONName(ptr, "doesNotExist") assert.False(t, ok) assert.Empty(t, nm) nm, ok = provider.GetJSONName(ptr, "Ignored") assert.False(t, ok) assert.Empty(t, nm) nms := provider.GetJSONNames(ptr) assert.Len(t, nms, 2) assert.Len(t, provider.index, 1) } func TestJSONConcatenation(t *testing.T) { assert.Nil(t, ConcatJSON()) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`)), []byte(`{"id":1}`)) assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{}`)), []byte(`{}`)) assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[]`)), []byte(`[]`)) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`)), []byte(`{"id":1,"name":"Rachel"}`)) assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`)), []byte(`[{"id":1},{"name":"Rachel"}]`)) assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{"name":"Rachel"}`)), []byte(`{"name":"Rachel"}`)) assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[{"name":"Rachel"}]`)), []byte(`[{"name":"Rachel"}]`)) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{}`)), []byte(`{"id":1}`)) assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[]`)), []byte(`[{"id":1}]`)) assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{}`), []byte(`{}`)), []byte(`{}`)) assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[]`), []byte(`[]`)), []byte(`[]`)) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`), []byte(`{"age":32}`)), []byte(`{"id":1,"name":"Rachel","age":32}`)) assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`), []byte(`[{"age":32}]`)), []byte(`[{"id":1},{"name":"Rachel"},{"age":32}]`)) assert.Equal(t, ConcatJSON([]byte(`{}`), []byte(`{"name":"Rachel"}`), []byte(`{"age":32}`)), []byte(`{"name":"Rachel","age":32}`)) assert.Equal(t, ConcatJSON([]byte(`[]`), []byte(`[{"name":"Rachel"}]`), []byte(`[{"age":32}]`)), []byte(`[{"name":"Rachel"},{"age":32}]`)) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{}`), []byte(`{"age":32}`)), []byte(`{"id":1,"age":32}`)) assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[]`), []byte(`[{"age":32}]`)), []byte(`[{"id":1},{"age":32}]`)) assert.Equal(t, ConcatJSON([]byte(`{"id":1}`), []byte(`{"name":"Rachel"}`), []byte(`{}`)), []byte(`{"id":1,"name":"Rachel"}`)) assert.Equal(t, ConcatJSON([]byte(`[{"id":1}]`), []byte(`[{"name":"Rachel"}]`), []byte(`[]`)), []byte(`[{"id":1},{"name":"Rachel"}]`)) // add test on null assert.Equal(t, ConcatJSON([]byte(nil)), []byte(nil)) assert.Equal(t, ConcatJSON([]byte(`null`)), []byte(nil)) assert.Equal(t, ConcatJSON([]byte(nil), []byte(`null`)), []byte(nil)) assert.Equal(t, ConcatJSON([]byte(`{"id":null}`), []byte(`null`)), []byte(`{"id":null}`)) assert.Equal(t, ConcatJSON([]byte(`{"id":null}`), []byte(`null`), []byte(`{"name":"Rachel"}`)), []byte(`{"id":null,"name":"Rachel"}`)) } type SharedCounters struct { Counter1 int64 `json:"counter1,omitempty"` Counter2 int64 `json:"counter2:,omitempty"` } type AggregationObject struct { SharedCounters Count int64 `json:"count,omitempty"` } func (m *AggregationObject) UnmarshalJSON(raw []byte) error { // AO0 var aO0 SharedCounters if err := ReadJSON(raw, &aO0); err != nil { return err } m.SharedCounters = aO0 // now for regular properties var propsAggregationObject struct { Count int64 `json:"count,omitempty"` } if err := ReadJSON(raw, &propsAggregationObject); err != nil { return err } m.Count = propsAggregationObject.Count return nil } // MarshalJSON marshals this object to a JSON structure func (m AggregationObject) MarshalJSON() ([]byte, error) { _parts := make([][]byte, 0, 1) aO0, err := WriteJSON(m.SharedCounters) if err != nil { return nil, err } _parts = append(_parts, aO0) // now for regular properties var propsAggregationObject struct { Count int64 `json:"count,omitempty"` } propsAggregationObject.Count = m.Count jsonDataPropsAggregationObject, errAggregationObject := WriteJSON(propsAggregationObject) if errAggregationObject != nil { return nil, errAggregationObject } _parts = append(_parts, jsonDataPropsAggregationObject) return ConcatJSON(_parts...), nil } func TestIssue2350(t *testing.T) { obj := AggregationObject{Count: 290, SharedCounters: SharedCounters{Counter1: 304, Counter2: 948}} rtjson, err := WriteJSON(obj) require.NoError(t, err) otjson, err := obj.MarshalJSON() require.NoError(t, err) require.JSONEq(t, string(rtjson), string(otjson)) var obj1 AggregationObject require.NoError(t, ReadJSON(rtjson, &obj1)) require.Equal(t, obj, obj1) var obj11 AggregationObject require.NoError(t, obj11.UnmarshalJSON(rtjson)) require.Equal(t, obj, obj11) jsons := `{"counter1":123,"counter2:":456,"count":999}` var obj2 AggregationObject require.NoError(t, ReadJSON([]byte(jsons), &obj2)) require.Equal(t, AggregationObject{SharedCounters: SharedCounters{Counter1: 123, Counter2: 456}, Count: 999}, obj2) } swag-0.22.8/loading.go000066400000000000000000000136301455341767200145310ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "fmt" "io" "log" "net/http" "net/url" "os" "path" "path/filepath" "runtime" "strings" "time" ) // LoadHTTPTimeout the default timeout for load requests var LoadHTTPTimeout = 30 * time.Second // LoadHTTPBasicAuthUsername the username to use when load requests require basic auth var LoadHTTPBasicAuthUsername = "" // LoadHTTPBasicAuthPassword the password to use when load requests require basic auth var LoadHTTPBasicAuthPassword = "" // LoadHTTPCustomHeaders an optional collection of custom HTTP headers for load requests var LoadHTTPCustomHeaders = map[string]string{} // LoadFromFileOrHTTP loads the bytes from a file or a remote http server based on the path passed in func LoadFromFileOrHTTP(pth string) ([]byte, error) { return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(LoadHTTPTimeout))(pth) } // LoadFromFileOrHTTPWithTimeout loads the bytes from a file or a remote http server based on the path passed in // timeout arg allows for per request overriding of the request timeout func LoadFromFileOrHTTPWithTimeout(pth string, timeout time.Duration) ([]byte, error) { return LoadStrategy(pth, os.ReadFile, loadHTTPBytes(timeout))(pth) } // LoadStrategy returns a loader function for a given path or URI. // // The load strategy returns the remote load for any path starting with `http`. // So this works for any URI with a scheme `http` or `https`. // // The fallback strategy is to call the local loader. // // The local loader takes a local file system path (absolute or relative) as argument, // or alternatively a `file://...` URI, **without host** (see also below for windows). // // There are a few liberalities, initially intended to be tolerant regarding the URI syntax, // especially on windows. // // Before the local loader is called, the given path is transformed: // - percent-encoded characters are unescaped // - simple paths (e.g. `./folder/file`) are passed as-is // - on windows, occurrences of `/` are replaced by `\`, so providing a relative path such a `folder/file` works too. // // For paths provided as URIs with the "file" scheme, please note that: // - `file://` is simply stripped. // This means that the host part of the URI is not parsed at all. // For example, `file:///folder/file" becomes "/folder/file`, // but `file://localhost/folder/file` becomes `localhost/folder/file` on unix systems. // Similarly, `file://./folder/file` yields `./folder/file`. // - on windows, `file://...` can take a host so as to specify an UNC share location. // // Reminder about windows-specifics: // - `file://host/folder/file` becomes an UNC path like `\\host\folder\file` (no port specification is supported) // - `file:///c:/folder/file` becomes `C:\folder\file` // - `file://c:/folder/file` is tolerated (without leading `/`) and becomes `c:\folder\file` func LoadStrategy(pth string, local, remote func(string) ([]byte, error)) func(string) ([]byte, error) { if strings.HasPrefix(pth, "http") { return remote } return func(p string) ([]byte, error) { upth, err := url.PathUnescape(p) if err != nil { return nil, err } if !strings.HasPrefix(p, `file://`) { // regular file path provided: just normalize slashes return local(filepath.FromSlash(upth)) } if runtime.GOOS != "windows" { // crude processing: this leaves full URIs with a host with a (mostly) unexpected result upth = strings.TrimPrefix(upth, `file://`) return local(filepath.FromSlash(upth)) } // windows-only pre-processing of file://... URIs // support for canonical file URIs on windows. u, err := url.Parse(filepath.ToSlash(upth)) if err != nil { return nil, err } if u.Host != "" { // assume UNC name (volume share) // NOTE: UNC port not yet supported // when the "host" segment is a drive letter: // file://C:/folder/... => C:\folder upth = path.Clean(strings.Join([]string{u.Host, u.Path}, `/`)) if !strings.HasSuffix(u.Host, ":") && u.Host[0] != '.' { // tolerance: if we have a leading dot, this can't be a host // file://host/share/folder\... ==> \\host\share\path\folder upth = "//" + upth } } else { // no host, let's figure out if this is a drive letter upth = strings.TrimPrefix(upth, `file://`) first, _, _ := strings.Cut(strings.TrimPrefix(u.Path, "/"), "/") if strings.HasSuffix(first, ":") { // drive letter in the first segment: // file:///c:/folder/... ==> strip the leading slash upth = strings.TrimPrefix(upth, `/`) } } return local(filepath.FromSlash(upth)) } } func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) { return func(path string) ([]byte, error) { client := &http.Client{Timeout: timeout} req, err := http.NewRequest(http.MethodGet, path, nil) //nolint:noctx if err != nil { return nil, err } if LoadHTTPBasicAuthUsername != "" && LoadHTTPBasicAuthPassword != "" { req.SetBasicAuth(LoadHTTPBasicAuthUsername, LoadHTTPBasicAuthPassword) } for key, val := range LoadHTTPCustomHeaders { req.Header.Set(key, val) } resp, err := client.Do(req) defer func() { if resp != nil { if e := resp.Body.Close(); e != nil { log.Println(e) } } }() if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status) } return io.ReadAll(resp.Body) } } swag-0.22.8/loading_test.go000066400000000000000000000245041455341767200155720ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "net/http" "net/http/httptest" "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const ( validUsername = "fake-user" validPassword = "correct-password" invalidPassword = "incorrect-password" sharedHeaderKey = "X-Myapp" sharedHeaderValue = "MySecretKey" ) func TestLoadFromHTTP(t *testing.T) { _, err := LoadFromFileOrHTTP("httx://12394:abd") require.Error(t, err) serv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(http.StatusNotFound) })) defer serv.Close() _, err = LoadFromFileOrHTTP(serv.URL) require.Error(t, err) ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(http.StatusOK) _, _ = rw.Write([]byte("the content")) })) defer ts2.Close() d, err := LoadFromFileOrHTTP(ts2.URL) require.NoError(t, err) assert.Equal(t, []byte("the content"), d) ts3 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { u, p, ok := r.BasicAuth() if ok && u == validUsername && p == validPassword { rw.WriteHeader(http.StatusOK) } else { rw.WriteHeader(http.StatusForbidden) } })) defer ts3.Close() // no auth _, err = LoadFromFileOrHTTP(ts3.URL) require.Error(t, err) // basic auth, invalide credentials LoadHTTPBasicAuthUsername = validUsername LoadHTTPBasicAuthPassword = invalidPassword _, err = LoadFromFileOrHTTP(ts3.URL) require.Error(t, err) // basic auth, valid credentials LoadHTTPBasicAuthUsername = validUsername LoadHTTPBasicAuthPassword = validPassword _, err = LoadFromFileOrHTTP(ts3.URL) require.NoError(t, err) ts4 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { myHeaders := r.Header[sharedHeaderKey] ok := false for _, v := range myHeaders { if v == sharedHeaderValue { ok = true break } } if ok { rw.WriteHeader(http.StatusOK) } else { rw.WriteHeader(http.StatusForbidden) } })) defer ts4.Close() _, err = LoadFromFileOrHTTP(ts4.URL) require.Error(t, err) LoadHTTPCustomHeaders[sharedHeaderKey] = sharedHeaderValue _, err = LoadFromFileOrHTTP(ts4.URL) require.NoError(t, err) // clean up for future tests LoadHTTPBasicAuthUsername = "" LoadHTTPBasicAuthPassword = "" LoadHTTPCustomHeaders = map[string]string{} } func TestLoadHTTPBytes(t *testing.T) { _, err := LoadFromFileOrHTTP("httx://12394:abd") require.Error(t, err) serv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.WriteHeader(http.StatusNotFound) })) defer serv.Close() _, err = LoadFromFileOrHTTP(serv.URL) require.Error(t, err) ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.WriteHeader(http.StatusOK) _, _ = rw.Write([]byte("the content")) })) defer ts2.Close() d, err := LoadFromFileOrHTTP(ts2.URL) require.NoError(t, err) assert.Equal(t, []byte("the content"), d) } func TestLoadStrategy(t *testing.T) { loader := func(p string) ([]byte, error) { return []byte(yamlPetStore), nil } remLoader := func(p string) ([]byte, error) { return []byte("not it"), nil } ld := LoadStrategy("blah", loader, remLoader) b, _ := ld("") assert.Equal(t, []byte(yamlPetStore), b) serv := httptest.NewServer(http.HandlerFunc(yamlPestoreServer)) defer serv.Close() s, err := YAMLDoc(serv.URL) require.NoError(t, err) require.NotNil(t, s) ts2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.WriteHeader(http.StatusNotFound) _, _ = rw.Write([]byte("\n")) })) defer ts2.Close() _, err = YAMLDoc(ts2.URL) require.Error(t, err) } func TestLoadStrategyFile(t *testing.T) { const ( thisIsIt = "thisIsIt" thisIsNotIt = "not it" ) type strategyTest struct { Title string Path string Expected string ExpectedWindows string ExpectError bool } t.Run("with local file strategy", func(t *testing.T) { loader := func(called *bool, pth *string) func(string) ([]byte, error) { return func(p string) ([]byte, error) { *called = true *pth = p return []byte(thisIsIt), nil } } remLoader := func(p string) ([]byte, error) { return []byte(thisIsNotIt), nil } for _, toPin := range []strategyTest{ { Title: "valid fully qualified local URI, with rooted path", Path: "file:///a/c/myfile.yaml", Expected: "/a/c/myfile.yaml", ExpectedWindows: `\a\c\myfile.yaml`, }, { Title: "local URI with scheme, with host segment before path", Path: "file://a/c/myfile.yaml", Expected: "a/c/myfile.yaml", ExpectedWindows: `\\a\c\myfile.yaml`, // UNC host }, { Title: "local URI with scheme, with escaped characters", Path: "file://a/c/myfile%20%28x86%29.yaml", Expected: "a/c/myfile (x86).yaml", ExpectedWindows: `\\a\c\myfile (x86).yaml`, }, { Title: "local URI with scheme, rooted, with escaped characters", Path: "file:///a/c/myfile%20%28x86%29.yaml", Expected: "/a/c/myfile (x86).yaml", ExpectedWindows: `\a\c\myfile (x86).yaml`, }, { Title: "local URI with scheme, unescaped, with host", Path: "file://a/c/myfile (x86).yaml", Expected: "a/c/myfile (x86).yaml", ExpectedWindows: `\\a\c\myfile (x86).yaml`, }, { Title: "local URI with scheme, rooted, unescaped", Path: "file:///a/c/myfile (x86).yaml", Expected: "/a/c/myfile (x86).yaml", ExpectedWindows: `\a\c\myfile (x86).yaml`, }, { Title: "file URI with drive letter and backslashes, as a relative Windows path", Path: `file://C:\a\c\myfile.yaml`, Expected: `C:\a\c\myfile.yaml`, // outcome on all platforms, not only windows }, { Title: "file URI with drive letter and backslashes, as a rooted Windows path", Path: `file:///C:\a\c\myfile.yaml`, Expected: `/C:\a\c\myfile.yaml`, // on non-windows, this results most likely in a wrong path ExpectedWindows: `C:\a\c\myfile.yaml`, // on windows, we know that C: is a drive letter, so /C: becomes C: }, { Title: "file URI with escaped backslashes", Path: `file://C%3A%5Ca%5Cc%5Cmyfile.yaml`, Expected: `C:\a\c\myfile.yaml`, // outcome on all platforms, not only windows }, { Title: "file URI with escaped backslashes, rooted", Path: `file:///C%3A%5Ca%5Cc%5Cmyfile.yaml`, Expected: `/C:\a\c\myfile.yaml`, // outcome on non-windows (most likely not a desired path) ExpectedWindows: `C:\a\c\myfile.yaml`, // outcome on windows }, { Title: "URI with the file scheme, host omitted: relative path with extra dots", Path: `file://./a/c/d/../myfile.yaml`, Expected: `./a/c/d/../myfile.yaml`, ExpectedWindows: `a\c\myfile.yaml`, // on windows, extra processing cleans the path }, { Title: "relative URI without the file scheme, rooted path", Path: `/a/c/myfile.yaml`, Expected: `/a/c/myfile.yaml`, ExpectedWindows: `\a\c\myfile.yaml`, // there is no drive letter, this would probably result in a wrong path on Windows }, { Title: "relative URI without the file scheme, relative path", Path: `a/c/myfile.yaml`, Expected: `a/c/myfile.yaml`, ExpectedWindows: `a\c\myfile.yaml`, }, { Title: "relative URI without the file scheme, relative path with dots", Path: `./a/c/myfile.yaml`, Expected: `./a/c/myfile.yaml`, ExpectedWindows: `.\a\c\myfile.yaml`, }, { Title: "relative URI without the file scheme, relative path with extra dots", Path: `./a/c/../myfile.yaml`, Expected: `./a/c/../myfile.yaml`, ExpectedWindows: `.\a\c\..\myfile.yaml`, }, { Title: "relative URI without the file scheme, windows slashed-path with drive letter", Path: `A:/a/c/myfile.yaml`, Expected: `A:/a/c/myfile.yaml`, // on non-windows, this results most likely in a wrong path ExpectedWindows: `A:\a\c\myfile.yaml`, // on windows, slashes are converted }, { Title: "relative URI without the file scheme, windows backslashed-path with drive letter", Path: `A:\a\c\myfile.yaml`, Expected: `A:\a\c\myfile.yaml`, // on non-windows, this results most likely in a wrong path ExpectedWindows: `A:\a\c\myfile.yaml`, }, { Title: "URI with file scheme, host as Windows UNC name", Path: `file://host/share/folder/myfile.yaml`, Expected: `host/share/folder/myfile.yaml`, // there is no host component accounted for ExpectedWindows: `\\host\share\folder\myfile.yaml`, // on windows, the host is interpreted as an UNC host for a file share }, // TODO: invalid URI (cannot unescape/parse path) } { tc := toPin t.Run(tc.Title, func(t *testing.T) { var ( called bool pth string ) ld := LoadStrategy("local", loader(&called, &pth), remLoader) b, err := ld(tc.Path) if tc.ExpectError { require.Error(t, err) assert.True(t, called) return } require.NoError(t, err) assert.True(t, called) assert.Equal(t, []byte(thisIsIt), b) if tc.ExpectedWindows != "" && runtime.GOOS == "windows" { assert.Equalf(t, tc.ExpectedWindows, pth, "expected local LoadStrategy(%q) to open: %q (windows)", tc.Path, tc.ExpectedWindows, ) return } assert.Equalf(t, tc.Expected, pth, "expected local LoadStrategy(%q) to open: %q (any OS)", tc.Path, tc.Expected, ) }) } }) } swag-0.22.8/name_lexem.go000066400000000000000000000035661455341767200152350ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "unicode" "unicode/utf8" ) type ( lexemKind uint8 nameLexem struct { original string matchedInitialism string kind lexemKind } ) const ( lexemKindCasualName lexemKind = iota lexemKindInitialismName ) func newInitialismNameLexem(original, matchedInitialism string) nameLexem { return nameLexem{ kind: lexemKindInitialismName, original: original, matchedInitialism: matchedInitialism, } } func newCasualNameLexem(original string) nameLexem { return nameLexem{ kind: lexemKindCasualName, original: original, } } func (l nameLexem) GetUnsafeGoName() string { if l.kind == lexemKindInitialismName { return l.matchedInitialism } var ( first rune rest string ) for i, orig := range l.original { if i == 0 { first = orig continue } if i > 0 { rest = l.original[i:] break } } if len(l.original) > 1 { b := poolOfBuffers.BorrowBuffer(utf8.UTFMax + len(rest)) defer func() { poolOfBuffers.RedeemBuffer(b) }() b.WriteRune(unicode.ToUpper(first)) b.WriteString(lower(rest)) return b.String() } return l.original } func (l nameLexem) GetOriginal() string { return l.original } func (l nameLexem) IsInitialism() bool { return l.kind == lexemKindInitialismName } swag-0.22.8/net.go000066400000000000000000000021051455341767200136750ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "net" "strconv" ) // SplitHostPort splits a network address into a host and a port. // The port is -1 when there is no port to be found func SplitHostPort(addr string) (host string, port int, err error) { h, p, err := net.SplitHostPort(addr) if err != nil { return "", -1, err } if p == "" { return "", -1, &net.AddrError{Err: "missing port in address", Addr: addr} } pi, err := strconv.Atoi(p) if err != nil { return "", -1, err } return h, pi, nil } swag-0.22.8/net_test.go000066400000000000000000000023321455341767200147360ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSplitHostPort(t *testing.T) { data := []struct { Input string Host string Port int Err bool }{ {"localhost:3933", "localhost", 3933, false}, {"localhost:yellow", "", -1, true}, {"localhost", "", -1, true}, {"localhost:", "", -1, true}, {"localhost:3933", "localhost", 3933, false}, } for _, e := range data { h, p, err := SplitHostPort(e.Input) if !e.Err { require.NoError(t, err) } else { require.Error(t, err) } assert.Equal(t, e.Host, h) assert.Equal(t, e.Port, p) } } swag-0.22.8/path.go000066400000000000000000000032031455341767200140430ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "os" "path/filepath" "runtime" "strings" ) const ( // GOPATHKey represents the env key for gopath GOPATHKey = "GOPATH" ) // FindInSearchPath finds a package in a provided lists of paths func FindInSearchPath(searchPath, pkg string) string { pathsList := filepath.SplitList(searchPath) for _, path := range pathsList { if evaluatedPath, err := filepath.EvalSymlinks(filepath.Join(path, "src", pkg)); err == nil { if _, err := os.Stat(evaluatedPath); err == nil { return evaluatedPath } } } return "" } // FindInGoSearchPath finds a package in the $GOPATH:$GOROOT func FindInGoSearchPath(pkg string) string { return FindInSearchPath(FullGoSearchPath(), pkg) } // FullGoSearchPath gets the search paths for finding packages func FullGoSearchPath() string { allPaths := os.Getenv(GOPATHKey) if allPaths == "" { allPaths = filepath.Join(os.Getenv("HOME"), "go") } if allPaths != "" { allPaths = strings.Join([]string{allPaths, runtime.GOROOT()}, ":") } else { allPaths = runtime.GOROOT() } return allPaths } swag-0.22.8/path_test.go000066400000000000000000000063331455341767200151110ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "os" "path" "path/filepath" "runtime" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func makeDirStructure(tgt string) (string, string, error) { if tgt == "" { tgt = "pkgpaths" } td, err := os.MkdirTemp("", tgt) if err != nil { return "", "", err } td2, err := os.MkdirTemp("", tgt+"-2") if err != nil { return "", "", err } realPath := filepath.Join(td, "src", "foo", "bar") if err := os.MkdirAll(realPath, os.ModePerm); err != nil { return "", "", err } linkPathBase := filepath.Join(td, "src", "baz") if err := os.MkdirAll(linkPathBase, os.ModePerm); err != nil { return "", "", err } linkPath := filepath.Join(linkPathBase, "das") if err := os.Symlink(realPath, linkPath); err != nil { return "", "", err } realPath = filepath.Join(td2, "src", "fuu", "bir") if err := os.MkdirAll(realPath, os.ModePerm); err != nil { return "", "", err } linkPathBase = filepath.Join(td2, "src", "biz") if err := os.MkdirAll(linkPathBase, os.ModePerm); err != nil { return "", "", err } linkPath = filepath.Join(linkPathBase, "dis") if err := os.Symlink(realPath, linkPath); err != nil { return "", "", err } return td, td2, nil } func TestFindPackage(t *testing.T) { pth, pth2, err := makeDirStructure("") if err != nil { t.Fatal(err) } defer func() { os.RemoveAll(pth) os.RemoveAll(pth2) }() searchPath := pth + string(filepath.ListSeparator) + pth2 // finds package when real name mentioned pkg := FindInSearchPath(searchPath, "foo/bar") assert.NotEmpty(t, pkg) assertPath(t, path.Join(pth, "src", "foo", "bar"), pkg) // finds package when real name is mentioned in secondary pkg = FindInSearchPath(searchPath, "fuu/bir") assert.NotEmpty(t, pkg) assertPath(t, path.Join(pth2, "src", "fuu", "bir"), pkg) // finds package when symlinked pkg = FindInSearchPath(searchPath, "baz/das") assert.NotEmpty(t, pkg) assertPath(t, path.Join(pth, "src", "foo", "bar"), pkg) // finds package when symlinked in secondary pkg = FindInSearchPath(searchPath, "biz/dis") assert.NotEmpty(t, pkg) assertPath(t, path.Join(pth2, "src", "fuu", "bir"), pkg) // return empty string when nothing is found pkg = FindInSearchPath(searchPath, "not/there") assert.Empty(t, pkg) } //nolint:unparam func assertPath(t testing.TB, expected, actual string) bool { fp, err := filepath.EvalSymlinks(expected) require.NoError(t, err) return assert.Equal(t, fp, actual) } func TestFullGOPATH(t *testing.T) { os.Unsetenv(GOPATHKey) ngp := "/some/where:/other/place" t.Setenv(GOPATHKey, ngp) expected := ngp + ":" + runtime.GOROOT() assert.Equal(t, expected, FullGoSearchPath()) } swag-0.22.8/split.go000066400000000000000000000254161455341767200142540ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "bytes" "sync" "unicode" "unicode/utf8" ) type ( splitter struct { initialisms []string initialismsRunes [][]rune initialismsUpperCased [][]rune // initialisms cached in their trimmed, upper-cased version postSplitInitialismCheck bool } splitterOption func(*splitter) initialismMatch struct { body []rune start, end int complete bool } initialismMatches []initialismMatch ) type ( // memory pools of temporary objects. // // These are used to recycle temporarily allocated objects // and relieve the GC from undue pressure. matchesPool struct { *sync.Pool } buffersPool struct { *sync.Pool } lexemsPool struct { *sync.Pool } splittersPool struct { *sync.Pool } ) var ( // poolOfMatches holds temporary slices for recycling during the initialism match process poolOfMatches = matchesPool{ Pool: &sync.Pool{ New: func() any { s := make(initialismMatches, 0, maxAllocMatches) return &s }, }, } poolOfBuffers = buffersPool{ Pool: &sync.Pool{ New: func() any { return new(bytes.Buffer) }, }, } poolOfLexems = lexemsPool{ Pool: &sync.Pool{ New: func() any { s := make([]nameLexem, 0, maxAllocMatches) return &s }, }, } poolOfSplitters = splittersPool{ Pool: &sync.Pool{ New: func() any { s := newSplitter() return &s }, }, } ) // nameReplaceTable finds a word representation for special characters. func nameReplaceTable(r rune) (string, bool) { switch r { case '@': return "At ", true case '&': return "And ", true case '|': return "Pipe ", true case '$': return "Dollar ", true case '!': return "Bang ", true case '-': return "", true case '_': return "", true default: return "", false } } // split calls the splitter. // // Use newSplitter for more control and options func split(str string) []string { s := poolOfSplitters.BorrowSplitter() lexems := s.split(str) result := make([]string, 0, len(*lexems)) for _, lexem := range *lexems { result = append(result, lexem.GetOriginal()) } poolOfLexems.RedeemLexems(lexems) poolOfSplitters.RedeemSplitter(s) return result } func newSplitter(options ...splitterOption) splitter { s := splitter{ postSplitInitialismCheck: false, initialisms: initialisms, initialismsRunes: initialismsRunes, initialismsUpperCased: initialismsUpperCased, } for _, option := range options { option(&s) } return s } // withPostSplitInitialismCheck allows to catch initialisms after main split process func withPostSplitInitialismCheck(s *splitter) { s.postSplitInitialismCheck = true } func (p matchesPool) BorrowMatches() *initialismMatches { s := p.Get().(*initialismMatches) *s = (*s)[:0] // reset slice, keep allocated capacity return s } func (p buffersPool) BorrowBuffer(size int) *bytes.Buffer { s := p.Get().(*bytes.Buffer) s.Reset() if s.Cap() < size { s.Grow(size) } return s } func (p lexemsPool) BorrowLexems() *[]nameLexem { s := p.Get().(*[]nameLexem) *s = (*s)[:0] // reset slice, keep allocated capacity return s } func (p splittersPool) BorrowSplitter(options ...splitterOption) *splitter { s := p.Get().(*splitter) s.postSplitInitialismCheck = false // reset options for _, apply := range options { apply(s) } return s } func (p matchesPool) RedeemMatches(s *initialismMatches) { p.Put(s) } func (p buffersPool) RedeemBuffer(s *bytes.Buffer) { p.Put(s) } func (p lexemsPool) RedeemLexems(s *[]nameLexem) { p.Put(s) } func (p splittersPool) RedeemSplitter(s *splitter) { p.Put(s) } func (m initialismMatch) isZero() bool { return m.start == 0 && m.end == 0 } func (s splitter) split(name string) *[]nameLexem { nameRunes := []rune(name) matches := s.gatherInitialismMatches(nameRunes) if matches == nil { return poolOfLexems.BorrowLexems() } return s.mapMatchesToNameLexems(nameRunes, matches) } func (s splitter) gatherInitialismMatches(nameRunes []rune) *initialismMatches { var matches *initialismMatches for currentRunePosition, currentRune := range nameRunes { // recycle these allocations as we loop over runes // with such recycling, only 2 slices should be allocated per call // instead of o(n). newMatches := poolOfMatches.BorrowMatches() // check current initialism matches if matches != nil { // skip first iteration for _, match := range *matches { if keepCompleteMatch := match.complete; keepCompleteMatch { *newMatches = append(*newMatches, match) continue } // drop failed match currentMatchRune := match.body[currentRunePosition-match.start] if currentMatchRune != currentRune { continue } // try to complete ongoing match if currentRunePosition-match.start == len(match.body)-1 { // we are close; the next step is to check the symbol ahead // if it is a small letter, then it is not the end of match // but beginning of the next word if currentRunePosition < len(nameRunes)-1 { nextRune := nameRunes[currentRunePosition+1] if newWord := unicode.IsLower(nextRune); newWord { // oh ok, it was the start of a new word continue } } match.complete = true match.end = currentRunePosition } *newMatches = append(*newMatches, match) } } // check for new initialism matches for i := range s.initialisms { initialismRunes := s.initialismsRunes[i] if initialismRunes[0] == currentRune { *newMatches = append(*newMatches, initialismMatch{ start: currentRunePosition, body: initialismRunes, complete: false, }) } } if matches != nil { poolOfMatches.RedeemMatches(matches) } matches = newMatches } // up to the caller to redeem this last slice return matches } func (s splitter) mapMatchesToNameLexems(nameRunes []rune, matches *initialismMatches) *[]nameLexem { nameLexems := poolOfLexems.BorrowLexems() var lastAcceptedMatch initialismMatch for _, match := range *matches { if !match.complete { continue } if firstMatch := lastAcceptedMatch.isZero(); firstMatch { s.appendBrokenDownCasualString(nameLexems, nameRunes[:match.start]) *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body))) lastAcceptedMatch = match continue } if overlappedMatch := match.start <= lastAcceptedMatch.end; overlappedMatch { continue } middle := nameRunes[lastAcceptedMatch.end+1 : match.start] s.appendBrokenDownCasualString(nameLexems, middle) *nameLexems = append(*nameLexems, s.breakInitialism(string(match.body))) lastAcceptedMatch = match } // we have not found any accepted matches if lastAcceptedMatch.isZero() { *nameLexems = (*nameLexems)[:0] s.appendBrokenDownCasualString(nameLexems, nameRunes) } else if lastAcceptedMatch.end+1 != len(nameRunes) { rest := nameRunes[lastAcceptedMatch.end+1:] s.appendBrokenDownCasualString(nameLexems, rest) } poolOfMatches.RedeemMatches(matches) return nameLexems } func (s splitter) breakInitialism(original string) nameLexem { return newInitialismNameLexem(original, original) } func (s splitter) appendBrokenDownCasualString(segments *[]nameLexem, str []rune) { currentSegment := poolOfBuffers.BorrowBuffer(len(str)) // unlike strings.Builder, bytes.Buffer initial storage can reused defer func() { poolOfBuffers.RedeemBuffer(currentSegment) }() addCasualNameLexem := func(original string) { *segments = append(*segments, newCasualNameLexem(original)) } addInitialismNameLexem := func(original, match string) { *segments = append(*segments, newInitialismNameLexem(original, match)) } var addNameLexem func(string) if s.postSplitInitialismCheck { addNameLexem = func(original string) { for i := range s.initialisms { if isEqualFoldIgnoreSpace(s.initialismsUpperCased[i], original) { addInitialismNameLexem(original, s.initialisms[i]) return } } addCasualNameLexem(original) } } else { addNameLexem = addCasualNameLexem } for _, rn := range str { if replace, found := nameReplaceTable(rn); found { if currentSegment.Len() > 0 { addNameLexem(currentSegment.String()) currentSegment.Reset() } if replace != "" { addNameLexem(replace) } continue } if !unicode.In(rn, unicode.L, unicode.M, unicode.N, unicode.Pc) { if currentSegment.Len() > 0 { addNameLexem(currentSegment.String()) currentSegment.Reset() } continue } if unicode.IsUpper(rn) { if currentSegment.Len() > 0 { addNameLexem(currentSegment.String()) } currentSegment.Reset() } currentSegment.WriteRune(rn) } if currentSegment.Len() > 0 { addNameLexem(currentSegment.String()) } } // isEqualFoldIgnoreSpace is the same as strings.EqualFold, but // it ignores leading and trailing blank spaces in the compared // string. // // base is assumed to be composed of upper-cased runes, and be already // trimmed. // // This code is heavily inspired from strings.EqualFold. func isEqualFoldIgnoreSpace(base []rune, str string) bool { var i, baseIndex int // equivalent to b := []byte(str), but without data copy b := hackStringBytes(str) for i < len(b) { if c := b[i]; c < utf8.RuneSelf { // fast path for ASCII if c != ' ' && c != '\t' { break } i++ continue } // unicode case r, size := utf8.DecodeRune(b[i:]) if !unicode.IsSpace(r) { break } i += size } if i >= len(b) { return len(base) == 0 } for _, baseRune := range base { if i >= len(b) { break } if c := b[i]; c < utf8.RuneSelf { // single byte rune case (ASCII) if baseRune >= utf8.RuneSelf { return false } baseChar := byte(baseRune) if c != baseChar && !('a' <= c && c <= 'z' && c-'a'+'A' == baseChar) { return false } baseIndex++ i++ continue } // unicode case r, size := utf8.DecodeRune(b[i:]) if unicode.ToUpper(r) != baseRune { return false } baseIndex++ i += size } if baseIndex != len(base) { return false } // all passed: now we should only have blanks for i < len(b) { if c := b[i]; c < utf8.RuneSelf { // fast path for ASCII if c != ' ' && c != '\t' { return false } i++ continue } // unicode case r, size := utf8.DecodeRune(b[i:]) if !unicode.IsSpace(r) { return false } i += size } return true } swag-0.22.8/split_test.go000066400000000000000000000055031455341767200153060ustar00rootroot00000000000000package swag import ( "testing" "github.com/stretchr/testify/require" ) func TestSplitter(t *testing.T) { s := newSplitter(withPostSplitInitialismCheck) t.Run("should return an empty slice of lexems", func(t *testing.T) { lexems := s.split("") poolOfLexems.RedeemLexems(lexems) require.NotNil(t, lexems) require.Empty(t, lexems) }) } func TestIsEqualFoldIgnoreSpace(t *testing.T) { t.Run("should find equal", func(t *testing.T) { require.True(t, isEqualFoldIgnoreSpace([]rune(""), "")) require.True(t, isEqualFoldIgnoreSpace([]rune(""), " ")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), " a")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), "a ")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), " a ")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), "\ta\t")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), "a")) require.True(t, isEqualFoldIgnoreSpace([]rune("A"), "\u00A0a\u00A0")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " ab")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), "ab ")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " ab ")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " ab ")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " AB")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), "AB ")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " AB ")) require.True(t, isEqualFoldIgnoreSpace([]rune("AB"), " AB ")) require.True(t, isEqualFoldIgnoreSpace([]rune("À"), " à")) require.True(t, isEqualFoldIgnoreSpace([]rune("À"), "à ")) require.True(t, isEqualFoldIgnoreSpace([]rune("À"), " à ")) require.True(t, isEqualFoldIgnoreSpace([]rune("À"), " à ")) }) t.Run("should find different", func(t *testing.T) { require.False(t, isEqualFoldIgnoreSpace([]rune("A"), "")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), "")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), " b ")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), " b ")) require.False(t, isEqualFoldIgnoreSpace([]rune("AB"), " A B ")) require.False(t, isEqualFoldIgnoreSpace([]rune("AB"), " a b ")) require.False(t, isEqualFoldIgnoreSpace([]rune("AB"), " AB \u00A0\u00A0x")) require.False(t, isEqualFoldIgnoreSpace([]rune("AB"), " AB \u00A0\u00A0é")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), "")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), "")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), " b ")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), " b ")) require.False(t, isEqualFoldIgnoreSpace([]rune("A"), " à")) require.False(t, isEqualFoldIgnoreSpace([]rune("À"), " bà")) require.False(t, isEqualFoldIgnoreSpace([]rune("À"), "àb ")) require.False(t, isEqualFoldIgnoreSpace([]rune("À"), " a ")) require.False(t, isEqualFoldIgnoreSpace([]rune("À"), "Á")) }) } swag-0.22.8/string_bytes.go000066400000000000000000000007421455341767200156300ustar00rootroot00000000000000package swag import "unsafe" type internalString struct { Data unsafe.Pointer Len int } // hackStringBytes returns the (unsafe) underlying bytes slice of a string. func hackStringBytes(str string) []byte { p := (*internalString)(unsafe.Pointer(&str)).Data return unsafe.Slice((*byte)(p), len(str)) } /* * go1.20 version (for when go mod moves to a go1.20 requirement): func hackStringBytes(str string) []byte { return unsafe.Slice(unsafe.StringData(str), len(str)) } */ swag-0.22.8/util.go000066400000000000000000000212621455341767200140710ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "reflect" "strings" "unicode" "unicode/utf8" ) // GoNamePrefixFunc sets an optional rule to prefix go names // which do not start with a letter. // // The prefix function is assumed to return a string that starts with an upper case letter. // // e.g. to help convert "123" into "{prefix}123" // // The default is to prefix with "X" var GoNamePrefixFunc func(string) string func prefixFunc(name, in string) string { if GoNamePrefixFunc == nil { return "X" + in } return GoNamePrefixFunc(name) + in } const ( // collectionFormatComma = "csv" collectionFormatSpace = "ssv" collectionFormatTab = "tsv" collectionFormatPipe = "pipes" collectionFormatMulti = "multi" ) // JoinByFormat joins a string array by a known format (e.g. swagger's collectionFormat attribute): // // ssv: space separated value // tsv: tab separated value // pipes: pipe (|) separated value // csv: comma separated value (default) func JoinByFormat(data []string, format string) []string { if len(data) == 0 { return data } var sep string switch format { case collectionFormatSpace: sep = " " case collectionFormatTab: sep = "\t" case collectionFormatPipe: sep = "|" case collectionFormatMulti: return data default: sep = "," } return []string{strings.Join(data, sep)} } // SplitByFormat splits a string by a known format: // // ssv: space separated value // tsv: tab separated value // pipes: pipe (|) separated value // csv: comma separated value (default) func SplitByFormat(data, format string) []string { if data == "" { return nil } var sep string switch format { case collectionFormatSpace: sep = " " case collectionFormatTab: sep = "\t" case collectionFormatPipe: sep = "|" case collectionFormatMulti: return nil default: sep = "," } var result []string for _, s := range strings.Split(data, sep) { if ts := strings.TrimSpace(s); ts != "" { result = append(result, ts) } } return result } // Removes leading whitespaces func trim(str string) string { return strings.TrimSpace(str) } // Shortcut to strings.ToUpper() func upper(str string) string { return strings.ToUpper(trim(str)) } // Shortcut to strings.ToLower() func lower(str string) string { return strings.ToLower(trim(str)) } // Camelize an uppercased word func Camelize(word string) string { camelized := poolOfBuffers.BorrowBuffer(len(word)) defer func() { poolOfBuffers.RedeemBuffer(camelized) }() for pos, ru := range []rune(word) { if pos > 0 { camelized.WriteRune(unicode.ToLower(ru)) } else { camelized.WriteRune(unicode.ToUpper(ru)) } } return camelized.String() } // ToFileName lowercases and underscores a go type name func ToFileName(name string) string { in := split(name) out := make([]string, 0, len(in)) for _, w := range in { out = append(out, lower(w)) } return strings.Join(out, "_") } // ToCommandName lowercases and underscores a go type name func ToCommandName(name string) string { in := split(name) out := make([]string, 0, len(in)) for _, w := range in { out = append(out, lower(w)) } return strings.Join(out, "-") } // ToHumanNameLower represents a code name as a human series of words func ToHumanNameLower(name string) string { s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) in := s.split(name) poolOfSplitters.RedeemSplitter(s) out := make([]string, 0, len(*in)) for _, w := range *in { if !w.IsInitialism() { out = append(out, lower(w.GetOriginal())) } else { out = append(out, trim(w.GetOriginal())) } } poolOfLexems.RedeemLexems(in) return strings.Join(out, " ") } // ToHumanNameTitle represents a code name as a human series of words with the first letters titleized func ToHumanNameTitle(name string) string { s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) in := s.split(name) poolOfSplitters.RedeemSplitter(s) out := make([]string, 0, len(*in)) for _, w := range *in { original := trim(w.GetOriginal()) if !w.IsInitialism() { out = append(out, Camelize(original)) } else { out = append(out, original) } } poolOfLexems.RedeemLexems(in) return strings.Join(out, " ") } // ToJSONName camelcases a name which can be underscored or pascal cased func ToJSONName(name string) string { in := split(name) out := make([]string, 0, len(in)) for i, w := range in { if i == 0 { out = append(out, lower(w)) continue } out = append(out, Camelize(trim(w))) } return strings.Join(out, "") } // ToVarName camelcases a name which can be underscored or pascal cased func ToVarName(name string) string { res := ToGoName(name) if isInitialism(res) { return lower(res) } if len(res) <= 1 { return lower(res) } return lower(res[:1]) + res[1:] } // ToGoName translates a swagger name which can be underscored or camel cased to a name that golint likes func ToGoName(name string) string { s := poolOfSplitters.BorrowSplitter(withPostSplitInitialismCheck) lexems := s.split(name) poolOfSplitters.RedeemSplitter(s) defer func() { poolOfLexems.RedeemLexems(lexems) }() lexemes := *lexems if len(lexemes) == 0 { return "" } result := poolOfBuffers.BorrowBuffer(len(name)) defer func() { poolOfBuffers.RedeemBuffer(result) }() // check if not starting with a letter, upper case firstPart := lexemes[0].GetUnsafeGoName() if lexemes[0].IsInitialism() { firstPart = upper(firstPart) } if c := firstPart[0]; c < utf8.RuneSelf { // ASCII switch { case 'A' <= c && c <= 'Z': result.WriteString(firstPart) case 'a' <= c && c <= 'z': result.WriteByte(c - 'a' + 'A') result.WriteString(firstPart[1:]) default: result.WriteString(prefixFunc(name, firstPart)) // NOTE: no longer check if prefixFunc returns a string that starts with uppercase: // assume this is always the case } } else { // unicode firstRune, _ := utf8.DecodeRuneInString(firstPart) switch { case !unicode.IsLetter(firstRune): result.WriteString(prefixFunc(name, firstPart)) case !unicode.IsUpper(firstRune): result.WriteString(prefixFunc(name, firstPart)) /* result.WriteRune(unicode.ToUpper(firstRune)) result.WriteString(firstPart[offset:]) */ default: result.WriteString(firstPart) } } for _, lexem := range lexemes[1:] { goName := lexem.GetUnsafeGoName() // to support old behavior if lexem.IsInitialism() { goName = upper(goName) } result.WriteString(goName) } return result.String() } // ContainsStrings searches a slice of strings for a case-sensitive match func ContainsStrings(coll []string, item string) bool { for _, a := range coll { if a == item { return true } } return false } // ContainsStringsCI searches a slice of strings for a case-insensitive match func ContainsStringsCI(coll []string, item string) bool { for _, a := range coll { if strings.EqualFold(a, item) { return true } } return false } type zeroable interface { IsZero() bool } // IsZero returns true when the value passed into the function is a zero value. // This allows for safer checking of interface values. func IsZero(data interface{}) bool { v := reflect.ValueOf(data) // check for nil data switch v.Kind() { //nolint:exhaustive case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: if v.IsNil() { return true } } // check for things that have an IsZero method instead if vv, ok := data.(zeroable); ok { return vv.IsZero() } // continue with slightly more complex reflection switch v.Kind() { //nolint:exhaustive case reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Struct, reflect.Array: return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface()) case reflect.Invalid: return true default: return false } } // CommandLineOptionsGroup represents a group of user-defined command line options type CommandLineOptionsGroup struct { ShortDescription string LongDescription string Options interface{} } swag-0.22.8/util_benchmark_test.go000066400000000000000000000016511455341767200171420ustar00rootroot00000000000000package swag import ( "fmt" "io" "testing" ) func BenchmarkToXXXName(b *testing.B) { samples := []string{ "sample text", "sample-text", "sample_text", "sampleText", "sample 2 Text", "findThingById", "日本語sample 2 Text", "日本語findThingById", "findTHINGSbyID", } b.Run("ToGoName", benchmarkFunc(ToGoName, samples)) b.Run("ToVarName", benchmarkFunc(ToVarName, samples)) b.Run("ToFileName", benchmarkFunc(ToFileName, samples)) b.Run("ToCommandName", benchmarkFunc(ToCommandName, samples)) b.Run("ToHumanNameLower", benchmarkFunc(ToHumanNameLower, samples)) b.Run("ToHumanNameTitle", benchmarkFunc(ToHumanNameTitle, samples)) } func benchmarkFunc(fn func(string) string, samples []string) func(*testing.B) { return func(b *testing.B) { b.ResetTimer() b.ReportAllocs() var res string for i := 0; i < b.N; i++ { res = fn(samples[i%len(samples)]) } fmt.Fprintln(io.Discard, res) } } swag-0.22.8/util_test.go000066400000000000000000000327311455341767200151330ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "fmt" "strings" "testing" "time" "unicode" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type translationSample struct { str, out string } func titleize(s string) string { return strings.ToTitle(s[:1]) + lower(s[1:]) } func init() { AddInitialisms("elb", "cap", "capwd", "wd") } func TestIndexOfInitialismsSorted(t *testing.T) { configuredInitialisms := map[string]bool{ "ACL": true, "API": true, "ASCII": true, "CPU": true, "CSS": true, "DNS": true, "VM": true, "XML": true, "XMPP": true, "XSRF": true, "XSS": true, } goldenSample := []string{ "ASCII", "XMPP", "XSRF", "ACL", "API", "CPU", "CSS", "DNS", "XML", "XSS", "VM", } for i := 0; i < 50; i++ { sample := newIndexOfInitialisms().load(configuredInitialisms).sorted() failMsg := "equal sorted initialisms should be always equal" if !assert.Equal(t, goldenSample, sample, failMsg) { t.FailNow() } } } func TestHighUnicode(t *testing.T) { ss := "日本語sample 2 Text" rss := []rune(ss) require.False(t, rss[0] < unicode.MaxASCII && unicode.IsLetter(rss[0])) } const ( textTitle = "Text" blankText = " text" dashText = "-text" uscoreText = "_text" sampleTitle = "Sample" sampleString = "sample" sampleBlank = "sample " sampleDash = "sample-" sampleUscore = "sample_" ) func TestToGoName(t *testing.T) { samples := []translationSample{ {"@Type", "AtType"}, {"Sample@where", "SampleAtWhere"}, {"Id", "ID"}, {"SomethingTTLSeconds", "SomethingTTLSeconds"}, {"sample text", "SampleText"}, {"IPv6Address", "IPV6Address"}, {"IPv4Address", "IPV4Address"}, {"sample-text", "SampleText"}, {"sample_text", "SampleText"}, {"sampleText", "SampleText"}, {"sample 2 Text", "Sample2Text"}, {"findThingById", "FindThingByID"}, {"日本語sample 2 Text", "X日本語sample2Text"}, {"日本語findThingById", "X日本語findThingByID"}, {"findTHINGSbyID", "FindTHINGSbyID"}, {"x-isAnOptionalHeader0", "XIsAnOptionalHeader0"}, {"get$ref", "GetDollarRef"}, {"éget$ref", "ÉgetDollarRef"}, {"日get$ref", "X日getDollarRef"}, {"", ""}, {"?", ""}, {"!", "Bang"}, {"", ""}, } for _, k := range commonInitialisms.sorted() { k = upper(k) samples = append(samples, translationSample{sampleBlank + lower(k) + blankText, sampleTitle + k + textTitle}, translationSample{sampleDash + lower(k) + dashText, sampleTitle + k + textTitle}, translationSample{sampleUscore + lower(k) + uscoreText, sampleTitle + k + textTitle}, translationSample{sampleString + titleize(k) + textTitle, sampleTitle + k + textTitle}, translationSample{sampleBlank + lower(k), sampleTitle + k}, translationSample{sampleDash + lower(k), sampleTitle + k}, translationSample{sampleUscore + lower(k), sampleTitle + k}, translationSample{sampleString + titleize(k), sampleTitle + k}, translationSample{sampleBlank + titleize(k) + blankText, sampleTitle + k + textTitle}, translationSample{sampleDash + titleize(k) + dashText, sampleTitle + k + textTitle}, translationSample{sampleUscore + titleize(k) + uscoreText, sampleTitle + k + textTitle}, ) } for _, sample := range samples { result := ToGoName(sample.str) assert.Equal(t, sample.out, result, "ToGoName(%q) == %q but got %q", sample.str, sample.out, result) } } func TestContainsStringsCI(t *testing.T) { list := []string{"hello", "world", "and", "such"} assert.True(t, ContainsStringsCI(list, "hELLo")) assert.True(t, ContainsStringsCI(list, "world")) assert.True(t, ContainsStringsCI(list, "AND")) assert.False(t, ContainsStringsCI(list, "nuts")) } func TestContainsStrings(t *testing.T) { list := []string{"hello", "world", "and", "such"} assert.True(t, ContainsStrings(list, "hello")) assert.False(t, ContainsStrings(list, "hELLo")) assert.True(t, ContainsStrings(list, "world")) assert.False(t, ContainsStrings(list, "World")) assert.True(t, ContainsStrings(list, "and")) assert.False(t, ContainsStrings(list, "AND")) assert.False(t, ContainsStrings(list, "nuts")) } const ( collectionFormatComma = "csv" ) func TestSplitByFormat(t *testing.T) { expected := []string{"one", "two", "three"} for _, fmt := range []string{collectionFormatComma, collectionFormatPipe, collectionFormatTab, collectionFormatSpace, collectionFormatMulti} { var actual []string switch fmt { case collectionFormatMulti: assert.Nil(t, SplitByFormat("", fmt)) assert.Nil(t, SplitByFormat("blah", fmt)) case collectionFormatSpace: actual = SplitByFormat(strings.Join(expected, " "), fmt) assert.EqualValues(t, expected, actual) case collectionFormatPipe: actual = SplitByFormat(strings.Join(expected, "|"), fmt) assert.EqualValues(t, expected, actual) case collectionFormatTab: actual = SplitByFormat(strings.Join(expected, "\t"), fmt) assert.EqualValues(t, expected, actual) default: actual = SplitByFormat(strings.Join(expected, ","), fmt) assert.EqualValues(t, expected, actual) } } } func TestJoinByFormat(t *testing.T) { for _, fmt := range []string{collectionFormatComma, collectionFormatPipe, collectionFormatTab, collectionFormatSpace, collectionFormatMulti} { lval := []string{"one", "two", "three"} var expected []string switch fmt { case collectionFormatMulti: expected = lval case collectionFormatSpace: expected = []string{strings.Join(lval, " ")} case collectionFormatPipe: expected = []string{strings.Join(lval, "|")} case collectionFormatTab: expected = []string{strings.Join(lval, "\t")} default: expected = []string{strings.Join(lval, ",")} } assert.Nil(t, JoinByFormat(nil, fmt)) assert.EqualValues(t, expected, JoinByFormat(lval, fmt)) } } func TestToFileName(t *testing.T) { samples := []translationSample{ {"SampleText", "sample_text"}, {"FindThingByID", "find_thing_by_id"}, {"CAPWD.folwdBylc", "capwd_folwd_bylc"}, {"CAPWDfolwdBylc", "cap_w_dfolwd_bylc"}, {"CAP_WD_folwdBylc", "cap_wd_folwd_bylc"}, {"TypeOAI_alias", "type_oai_alias"}, {"Type_OAI_alias", "type_oai_alias"}, {"Type_OAIAlias", "type_oai_alias"}, {"ELB.HTTPLoadBalancer", "elb_http_load_balancer"}, {"elbHTTPLoadBalancer", "elb_http_load_balancer"}, {"ELBHTTPLoadBalancer", "elb_http_load_balancer"}, {"get$Ref", "get_dollar_ref"}, } for _, k := range commonInitialisms.sorted() { samples = append(samples, translationSample{sampleTitle + k + textTitle, sampleUscore + lower(k) + uscoreText}, ) } for _, sample := range samples { result := ToFileName(sample.str) assert.Equal(t, sample.out, ToFileName(sample.str), "ToFileName(%q) == %q but got %q", sample.str, sample.out, result) } } func TestToCommandName(t *testing.T) { samples := []translationSample{ {"SampleText", "sample-text"}, {"FindThingByID", "find-thing-by-id"}, {"elbHTTPLoadBalancer", "elb-http-load-balancer"}, {"get$ref", "get-dollar-ref"}, {"get!ref", "get-bang-ref"}, } for _, k := range commonInitialisms.sorted() { samples = append(samples, translationSample{sampleTitle + k + textTitle, sampleDash + lower(k) + dashText}, ) } for _, sample := range samples { assert.Equal(t, sample.out, ToCommandName(sample.str)) } } func TestToHumanName(t *testing.T) { samples := []translationSample{ {"Id", "Id"}, {"SampleText", "sample text"}, {"FindThingByID", "find thing by ID"}, {"elbHTTPLoadBalancer", "elb HTTP load balancer"}, } for _, k := range commonInitialisms.sorted() { samples = append(samples, translationSample{sampleTitle + k + textTitle, sampleBlank + k + blankText}, ) } for _, sample := range samples { assert.Equal(t, sample.out, ToHumanNameLower(sample.str)) } } func TestToJSONName(t *testing.T) { samples := []translationSample{ {"SampleText", "sampleText"}, {"FindThingByID", "findThingById"}, {"elbHTTPLoadBalancer", "elbHttpLoadBalancer"}, {"get$ref", "getDollarRef"}, {"get!ref", "getBangRef"}, } for _, k := range commonInitialisms.sorted() { samples = append(samples, translationSample{sampleTitle + k + textTitle, sampleString + titleize(k) + textTitle}, ) } for _, sample := range samples { assert.Equal(t, sample.out, ToJSONName(sample.str)) } } type SimpleZeroes struct { ID string Name string } type ZeroesWithTime struct { Time time.Time } type dummyZeroable struct { zero bool } func (d dummyZeroable) IsZero() bool { return d.zero } func TestIsZero(t *testing.T) { var strs [5]string var strss []string var a int var b int8 var c int16 var d int32 var e int64 var f uint var g uint8 var h uint16 var i uint32 var j uint64 var k map[string]string var l interface{} var m *SimpleZeroes var n string var o SimpleZeroes var p ZeroesWithTime var q time.Time data := []struct { Data interface{} Expected bool }{ {a, true}, {b, true}, {c, true}, {d, true}, {e, true}, {f, true}, {g, true}, {h, true}, {i, true}, {j, true}, {k, true}, {l, true}, {m, true}, {n, true}, {o, true}, {p, true}, {q, true}, {strss, true}, {strs, true}, {"", true}, {nil, true}, {1, false}, {0, true}, {int8(1), false}, {int8(0), true}, {int16(1), false}, {int16(0), true}, {int32(1), false}, {int32(0), true}, {int64(1), false}, {int64(0), true}, {uint(1), false}, {uint(0), true}, {uint8(1), false}, {uint8(0), true}, {uint16(1), false}, {uint16(0), true}, {uint32(1), false}, {uint32(0), true}, {uint64(1), false}, {uint64(0), true}, {0.0, true}, {0.1, false}, {float32(0.0), true}, {float32(0.1), false}, {float64(0.0), true}, {float64(0.1), false}, {[...]string{}, true}, {[...]string{"hello"}, false}, {[]string(nil), true}, {[]string{"a"}, false}, {&dummyZeroable{true}, true}, {&dummyZeroable{false}, false}, {(*dummyZeroable)(nil), true}, } for _, it := range data { assert.Equal(t, it.Expected, IsZero(it.Data), fmt.Sprintf("%#v", it.Data)) } } func TestCamelize(t *testing.T) { samples := []translationSample{ {"SampleText", "Sampletext"}, {"FindThingByID", "Findthingbyid"}, {"CAPWD.folwdBylc", "Capwd.folwdbylc"}, {"CAPWDfolwdBylc", "Capwdfolwdbylc"}, {"CAP_WD_folwdBylc", "Cap_wd_folwdbylc"}, {"TypeOAI_alias", "Typeoai_alias"}, {"Type_OAI_alias", "Type_oai_alias"}, {"Type_OAIAlias", "Type_oaialias"}, {"ELB.HTTPLoadBalancer", "Elb.httploadbalancer"}, {"elbHTTPLoadBalancer", "Elbhttploadbalancer"}, {"ELBHTTPLoadBalancer", "Elbhttploadbalancer"}, {"12ab", "12ab"}, {"get$Ref", "Get$ref"}, {"get!Ref", "Get!ref"}, } for _, sample := range samples { res := Camelize(sample.str) assert.Equalf(t, sample.out, res, "expected Camelize(%q)=%q, got %q", sample.str, sample.out, res) } } func TestToHumanNameTitle(t *testing.T) { samples := []translationSample{ {"SampleText", "Sample Text"}, {"FindThingByID", "Find Thing By ID"}, {"CAPWD.folwdBylc", "CAPWD Folwd Bylc"}, {"CAPWDfolwdBylc", "CAP W Dfolwd Bylc"}, {"CAP_WD_folwdBylc", "CAP WD Folwd Bylc"}, {"TypeOAI_alias", "Type OAI Alias"}, {"Type_OAI_alias", "Type OAI Alias"}, {"Type_OAIAlias", "Type OAI Alias"}, {"ELB.HTTPLoadBalancer", "ELB HTTP Load Balancer"}, {"elbHTTPLoadBalancer", "elb HTTP Load Balancer"}, {"ELBHTTPLoadBalancer", "ELB HTTP Load Balancer"}, {"get$ref", "Get Dollar Ref"}, {"get!ref", "Get Bang Ref"}, } for _, sample := range samples { res := ToHumanNameTitle(sample.str) assert.Equalf(t, sample.out, res, "expected ToHumanNameTitle(%q)=%q, got %q", sample.str, sample.out, res) } } func TestToVarName(t *testing.T) { samples := []translationSample{ {"SampleText", "sampleText"}, {"FindThingByID", "findThingByID"}, {"CAPWD.folwdBylc", "cAPWDFolwdBylc"}, {"CAPWDfolwdBylc", "cAPWDfolwdBylc"}, {"CAP_WD_folwdBylc", "cAPWDFolwdBylc"}, {"TypeOAI_alias", "typeOAIAlias"}, {"Type_OAI_alias", "typeOAIAlias"}, {"Type_OAIAlias", "typeOAIAlias"}, {"ELB.HTTPLoadBalancer", "eLBHTTPLoadBalancer"}, {"elbHTTPLoadBalancer", "eLBHTTPLoadBalancer"}, {"ELBHTTPLoadBalancer", "eLBHTTPLoadBalancer"}, {"Id", "id"}, {"HTTP", "http"}, {"A", "a"}, {"get$ref", "getDollarRef"}, {"get!ref", "getBangRef"}, } for _, sample := range samples { res := ToVarName(sample.str) assert.Equalf(t, sample.out, res, "expected ToVarName(%q)=%q, got %q", sample.str, sample.out, res) } } func TestToGoNameUnicode(t *testing.T) { defer func() { GoNamePrefixFunc = nil }() GoNamePrefixFunc = func(name string) string { // this is the pascalize func from go-swagger codegen arg := []rune(name) if len(arg) == 0 || arg[0] > '9' { return "" } if arg[0] == '+' { return "Plus" } if arg[0] == '-' { return "Minus" } return "Nr" } samples := []translationSample{ {"123_a", "Nr123a"}, {"!123_a", "Bang123a"}, {"+123_a", "Plus123a"}, {"abc", "Abc"}, {"éabc", "Éabc"}, {":éabc", "Éabc"}, {"get$ref", "GetDollarRef"}, {"get!ref", "GetBangRef"}, {"get&ref", "GetAndRef"}, {"get|ref", "GetPipeRef"}, // TODO: non unicode char } for _, sample := range samples { assert.Equal(t, sample.out, ToGoName(sample.str)) } } swag-0.22.8/yaml.go000066400000000000000000000267261455341767200140700ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "encoding/json" "fmt" "path/filepath" "reflect" "sort" "strconv" "github.com/mailru/easyjson/jlexer" "github.com/mailru/easyjson/jwriter" yaml "gopkg.in/yaml.v3" ) // YAMLMatcher matches yaml func YAMLMatcher(path string) bool { ext := filepath.Ext(path) return ext == ".yaml" || ext == ".yml" } // YAMLToJSON converts YAML unmarshaled data into json compatible data func YAMLToJSON(data interface{}) (json.RawMessage, error) { jm, err := transformData(data) if err != nil { return nil, err } b, err := WriteJSON(jm) return json.RawMessage(b), err } // BytesToYAMLDoc converts a byte slice into a YAML document func BytesToYAMLDoc(data []byte) (interface{}, error) { var document yaml.Node // preserve order that is present in the document if err := yaml.Unmarshal(data, &document); err != nil { return nil, err } if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode { return nil, fmt.Errorf("only YAML documents that are objects are supported") } return &document, nil } func yamlNode(root *yaml.Node) (interface{}, error) { switch root.Kind { case yaml.DocumentNode: return yamlDocument(root) case yaml.SequenceNode: return yamlSequence(root) case yaml.MappingNode: return yamlMapping(root) case yaml.ScalarNode: return yamlScalar(root) case yaml.AliasNode: return yamlNode(root.Alias) default: return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind) } } func yamlDocument(node *yaml.Node) (interface{}, error) { if len(node.Content) != 1 { return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content)) } return yamlNode(node.Content[0]) } func yamlMapping(node *yaml.Node) (interface{}, error) { m := make(JSONMapSlice, len(node.Content)/2) var j int for i := 0; i < len(node.Content); i += 2 { var nmi JSONMapItem k, err := yamlStringScalarC(node.Content[i]) if err != nil { return nil, fmt.Errorf("unable to decode YAML map key: %w", err) } nmi.Key = k v, err := yamlNode(node.Content[i+1]) if err != nil { return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err) } nmi.Value = v m[j] = nmi j++ } return m, nil } func yamlSequence(node *yaml.Node) (interface{}, error) { s := make([]interface{}, 0) for i := 0; i < len(node.Content); i++ { v, err := yamlNode(node.Content[i]) if err != nil { return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err) } s = append(s, v) } return s, nil } const ( // See https://yaml.org/type/ yamlStringScalar = "tag:yaml.org,2002:str" yamlIntScalar = "tag:yaml.org,2002:int" yamlBoolScalar = "tag:yaml.org,2002:bool" yamlFloatScalar = "tag:yaml.org,2002:float" yamlTimestamp = "tag:yaml.org,2002:timestamp" yamlNull = "tag:yaml.org,2002:null" ) func yamlScalar(node *yaml.Node) (interface{}, error) { switch node.LongTag() { case yamlStringScalar: return node.Value, nil case yamlBoolScalar: b, err := strconv.ParseBool(node.Value) if err != nil { return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err) } return b, nil case yamlIntScalar: i, err := strconv.ParseInt(node.Value, 10, 64) if err != nil { return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err) } return i, nil case yamlFloatScalar: f, err := strconv.ParseFloat(node.Value, 64) if err != nil { return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err) } return f, nil case yamlTimestamp: return node.Value, nil case yamlNull: return nil, nil //nolint:nilnil default: return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag()) } } func yamlStringScalarC(node *yaml.Node) (string, error) { if node.Kind != yaml.ScalarNode { return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind) } switch node.LongTag() { case yamlStringScalar, yamlIntScalar, yamlFloatScalar: return node.Value, nil default: return "", fmt.Errorf("YAML tag %q is not supported as map key", node.LongTag()) } } // JSONMapSlice represent a JSON object, with the order of keys maintained type JSONMapSlice []JSONMapItem // MarshalJSON renders a JSONMapSlice as JSON func (s JSONMapSlice) MarshalJSON() ([]byte, error) { w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty} s.MarshalEasyJSON(w) return w.BuildBytes() } // MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) { w.RawByte('{') ln := len(s) last := ln - 1 for i := 0; i < ln; i++ { s[i].MarshalEasyJSON(w) if i != last { // last item w.RawByte(',') } } w.RawByte('}') } // UnmarshalJSON makes a JSONMapSlice from JSON func (s *JSONMapSlice) UnmarshalJSON(data []byte) error { l := jlexer.Lexer{Data: data} s.UnmarshalEasyJSON(&l) return l.Error() } // UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) { if in.IsNull() { in.Skip() return } var result JSONMapSlice in.Delim('{') for !in.IsDelim('}') { var mi JSONMapItem mi.UnmarshalEasyJSON(in) result = append(result, mi) } *s = result } func (s JSONMapSlice) MarshalYAML() (interface{}, error) { var n yaml.Node n.Kind = yaml.DocumentNode var nodes []*yaml.Node for _, item := range s { nn, err := json2yaml(item.Value) if err != nil { return nil, err } ns := []*yaml.Node{ { Kind: yaml.ScalarNode, Tag: yamlStringScalar, Value: item.Key, }, nn, } nodes = append(nodes, ns...) } n.Content = []*yaml.Node{ { Kind: yaml.MappingNode, Content: nodes, }, } return yaml.Marshal(&n) } func isNil(input interface{}) bool { if input == nil { return true } kind := reflect.TypeOf(input).Kind() switch kind { //nolint:exhaustive case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan: return reflect.ValueOf(input).IsNil() default: return false } } func json2yaml(item interface{}) (*yaml.Node, error) { if isNil(item) { return &yaml.Node{ Kind: yaml.ScalarNode, Value: "null", }, nil } switch val := item.(type) { case JSONMapSlice: var n yaml.Node n.Kind = yaml.MappingNode for i := range val { childNode, err := json2yaml(&val[i].Value) if err != nil { return nil, err } n.Content = append(n.Content, &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlStringScalar, Value: val[i].Key, }, childNode) } return &n, nil case map[string]interface{}: var n yaml.Node n.Kind = yaml.MappingNode keys := make([]string, 0, len(val)) for k := range val { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { v := val[k] childNode, err := json2yaml(v) if err != nil { return nil, err } n.Content = append(n.Content, &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlStringScalar, Value: k, }, childNode) } return &n, nil case []interface{}: var n yaml.Node n.Kind = yaml.SequenceNode for i := range val { childNode, err := json2yaml(val[i]) if err != nil { return nil, err } n.Content = append(n.Content, childNode) } return &n, nil case string: return &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlStringScalar, Value: val, }, nil case float64: return &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlFloatScalar, Value: strconv.FormatFloat(val, 'f', -1, 64), }, nil case int64: return &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlIntScalar, Value: strconv.FormatInt(val, 10), }, nil case uint64: return &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlIntScalar, Value: strconv.FormatUint(val, 10), }, nil case bool: return &yaml.Node{ Kind: yaml.ScalarNode, Tag: yamlBoolScalar, Value: strconv.FormatBool(val), }, nil default: return nil, fmt.Errorf("unhandled type: %T", val) } } // JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice type JSONMapItem struct { Key string Value interface{} } // MarshalJSON renders a JSONMapItem as JSON func (s JSONMapItem) MarshalJSON() ([]byte, error) { w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty} s.MarshalEasyJSON(w) return w.BuildBytes() } // MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) { w.String(s.Key) w.RawByte(':') w.Raw(WriteJSON(s.Value)) } // UnmarshalJSON makes a JSONMapItem from JSON func (s *JSONMapItem) UnmarshalJSON(data []byte) error { l := jlexer.Lexer{Data: data} s.UnmarshalEasyJSON(&l) return l.Error() } // UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) { key := in.UnsafeString() in.WantColon() value := in.Interface() in.WantComma() s.Key = key s.Value = value } func transformData(input interface{}) (out interface{}, err error) { format := func(t interface{}) (string, error) { switch k := t.(type) { case string: return k, nil case uint: return strconv.FormatUint(uint64(k), 10), nil case uint8: return strconv.FormatUint(uint64(k), 10), nil case uint16: return strconv.FormatUint(uint64(k), 10), nil case uint32: return strconv.FormatUint(uint64(k), 10), nil case uint64: return strconv.FormatUint(k, 10), nil case int: return strconv.Itoa(k), nil case int8: return strconv.FormatInt(int64(k), 10), nil case int16: return strconv.FormatInt(int64(k), 10), nil case int32: return strconv.FormatInt(int64(k), 10), nil case int64: return strconv.FormatInt(k, 10), nil default: return "", fmt.Errorf("unexpected map key type, got: %T", k) } } switch in := input.(type) { case yaml.Node: return yamlNode(&in) case *yaml.Node: return yamlNode(in) case map[interface{}]interface{}: o := make(JSONMapSlice, 0, len(in)) for ke, va := range in { var nmi JSONMapItem if nmi.Key, err = format(ke); err != nil { return nil, err } v, ert := transformData(va) if ert != nil { return nil, ert } nmi.Value = v o = append(o, nmi) } return o, nil case []interface{}: len1 := len(in) o := make([]interface{}, len1) for i := 0; i < len1; i++ { o[i], err = transformData(in[i]) if err != nil { return nil, err } } return o, nil } return input, nil } // YAMLDoc loads a yaml document from either http or a file and converts it to json func YAMLDoc(path string) (json.RawMessage, error) { yamlDoc, err := YAMLData(path) if err != nil { return nil, err } data, err := YAMLToJSON(yamlDoc) if err != nil { return nil, err } return data, nil } // YAMLData loads a yaml document from either http or a file func YAMLData(path string) (interface{}, error) { data, err := LoadFromFileOrHTTP(path) if err != nil { return nil, err } return BytesToYAMLDoc(data) } swag-0.22.8/yaml_test.go000066400000000000000000000355651455341767200151300ustar00rootroot00000000000000// Copyright 2015 go-swagger maintainers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package swag import ( "encoding/json" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" yaml "gopkg.in/yaml.v3" ) func TestJSONToYAML(t *testing.T) { sd := `{"1":"the int key value","name":"a string value","y":"some value"}` var data JSONMapSlice require.NoError(t, json.Unmarshal([]byte(sd), &data)) y, err := data.MarshalYAML() require.NoError(t, err) const expected = `"1": the int key value name: a string value y: some value ` assert.Equal(t, expected, string(y.([]byte))) nstd := `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}` const nestpected = `"1": the int key value name: a string value y: some value tag: name: tag name ` var ndata JSONMapSlice require.NoError(t, json.Unmarshal([]byte(nstd), &ndata)) ny, err := ndata.MarshalYAML() require.NoError(t, err) assert.Equal(t, nestpected, string(ny.([]byte))) ydoc, err := BytesToYAMLDoc([]byte(fixtures2224)) require.NoError(t, err) b, err := YAMLToJSON(ydoc) require.NoError(t, err) var bdata JSONMapSlice require.NoError(t, json.Unmarshal(b, &bdata)) } func TestJSONToYAMLWithNull(t *testing.T) { const ( jazon = `{"1":"the int key value","name":null,"y":"some value"}` expected = `"1": the int key value name: null y: some value ` ) var data JSONMapSlice require.NoError(t, json.Unmarshal([]byte(jazon), &data)) ny, err := data.MarshalYAML() require.NoError(t, err) assert.Equal(t, expected, string(ny.([]byte))) } func TestMarshalYAML(t *testing.T) { t.Run("marshalYAML should be deterministic", func(t *testing.T) { const ( jazon = `{"1":"x","2":null,"3":{"a":1,"b":2,"c":3}}` expected = `"1": x "2": null "3": a: !!float 1 b: !!float 2 c: !!float 3 ` ) const iterations = 10 for n := 0; n < iterations; n++ { var data JSONMapSlice require.NoError(t, json.Unmarshal([]byte(jazon), &data)) ny, err := data.MarshalYAML() require.NoError(t, err) assert.Equal(t, expected, string(ny.([]byte))) } }) } func TestYAMLToJSON(t *testing.T) { sd := `--- 1: the int key value name: a string value 'y': some value ` var data yaml.Node _ = yaml.Unmarshal([]byte(sd), &data) d, err := YAMLToJSON(data) require.NoError(t, err) require.NotNil(t, d) assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value"}`, string(d)) ns := []*yaml.Node{ { Kind: yaml.ScalarNode, Value: "true", Tag: "!!bool", }, { Kind: yaml.ScalarNode, Value: "the bool value", Tag: "!!str", }, } data.Content[0].Content = append(data.Content[0].Content, ns...) d, err = YAMLToJSON(data) require.Error(t, err) require.Nil(t, d) data.Content[0].Content = data.Content[0].Content[:len(data.Content[0].Content)-2] tag := []*yaml.Node{ { Kind: yaml.ScalarNode, Value: "tag", Tag: "!!str", }, { Kind: yaml.MappingNode, Content: []*yaml.Node{ { Kind: yaml.ScalarNode, Value: "name", Tag: "!!str", }, { Kind: yaml.ScalarNode, Value: "tag name", Tag: "!!str", }, }, }, } data.Content[0].Content = append(data.Content[0].Content, tag...) d, err = YAMLToJSON(data) require.NoError(t, err) assert.Equal(t, `{"1":"the int key value","name":"a string value","y":"some value","tag":{"name":"tag name"}}`, string(d)) tag[1].Content = []*yaml.Node{ { Kind: yaml.ScalarNode, Value: "true", Tag: "!!bool", }, { Kind: yaml.ScalarNode, Value: "the bool tag name", Tag: "!!str", }, } d, err = YAMLToJSON(data) require.Error(t, err) require.Nil(t, d) var lst []interface{} lst = append(lst, "hello") d, err = YAMLToJSON(lst) require.NoError(t, err) require.NotNil(t, d) assert.Equal(t, []byte(`["hello"]`), []byte(d)) lst = append(lst, data) d, err = YAMLToJSON(lst) require.Error(t, err) require.Nil(t, d) _, err = BytesToYAMLDoc([]byte("- name: hello\n")) require.Error(t, err) dd, err := BytesToYAMLDoc([]byte("description: 'object created'\n")) require.NoError(t, err) d, err = YAMLToJSON(dd) require.NoError(t, err) assert.Equal(t, json.RawMessage(`{"description":"object created"}`), d) } var yamlPestoreServer = func(rw http.ResponseWriter, r *http.Request) { rw.WriteHeader(http.StatusOK) _, _ = rw.Write([]byte(yamlPetStore)) } func TestWithYKey(t *testing.T) { doc, err := BytesToYAMLDoc([]byte(withYKey)) require.NoError(t, err) _, err = YAMLToJSON(doc) require.NoError(t, err) doc, err = BytesToYAMLDoc([]byte(withQuotedYKey)) require.NoError(t, err) jsond, err := YAMLToJSON(doc) require.NoError(t, err) var yt struct { Definitions struct { Viewbox struct { Properties struct { Y struct { Type string `json:"type"` } `json:"y"` } `json:"properties"` } `json:"viewbox"` } `json:"definitions"` } require.NoError(t, json.Unmarshal(jsond, &yt)) assert.Equal(t, "integer", yt.Definitions.Viewbox.Properties.Y.Type) } func TestMapKeyTypes(t *testing.T) { dm := map[interface{}]interface{}{ 12345: "int", int8(1): "int8", int16(12345): "int16", int32(12345678): "int32", int64(12345678910): "int64", uint(12345): "uint", uint8(1): "uint8", uint16(12345): "uint16", uint32(12345678): "uint32", uint64(12345678910): "uint64", } _, err := YAMLToJSON(dm) require.NoError(t, err) } const fixtures2224 = `definitions: Time: type: string format: date-time x-go-type: import: package: time embedded: true type: Time x-nullable: true TimeAsObject: # <- time.Time is actually a struct type: string format: date-time x-go-type: import: package: time hints: kind: object embedded: true type: Time x-nullable: true Raw: x-go-type: import: package: encoding/json hints: kind: primitive embedded: true type: RawMessage Request: x-go-type: import: package: net/http hints: kind: object embedded: true type: Request RequestPointer: x-go-type: import: package: net/http hints: kind: object nullable: true embedded: true type: Request OldStyleImport: type: object x-go-type: import: package: net/http type: Request hints: noValidation: true OldStyleRenamed: type: object x-go-type: import: package: net/http type: Request hints: noValidation: true x-go-name: OldRenamed ObjectWithEmbedded: type: object properties: a: $ref: '#/definitions/Time' b: $ref: '#/definitions/Request' c: $ref: '#/definitions/TimeAsObject' d: $ref: '#/definitions/Raw' e: $ref: '#/definitions/JSONObject' f: $ref: '#/definitions/JSONMessage' g: $ref: '#/definitions/JSONObjectWithAlias' ObjectWithExternals: type: object properties: a: $ref: '#/definitions/OldStyleImport' b: $ref: '#/definitions/OldStyleRenamed' Base: properties: &base id: type: integer format: uint64 x-go-custom-tag: 'gorm:"primary_key"' FBID: type: integer format: uint64 x-go-custom-tag: 'gorm:"index"' created_at: $ref: "#/definitions/Time" updated_at: $ref: "#/definitions/Time" version: type: integer format: uint64 HotspotType: type: string enum: - A - B - C Hotspot: type: object allOf: - properties: *base - properties: access_points: type: array items: $ref: '#/definitions/AccessPoint' type: $ref: '#/definitions/HotspotType' required: - type AccessPoint: type: object allOf: - properties: *base - properties: mac_address: type: string x-go-custom-tag: 'gorm:"index;not null;unique"' hotspot_id: type: integer format: uint64 hotspot: $ref: '#/definitions/Hotspot' JSONObject: type: object additionalProperties: type: array items: $ref: '#/definitions/Raw' JSONObjectWithAlias: type: object additionalProperties: type: object properties: message: $ref: '#/definitions/JSONMessage' JSONMessage: $ref: '#/definitions/Raw' Incorrect: x-go-type: import: package: net hints: kind: array embedded: true type: Buffers x-nullable: true ` const withQuotedYKey = `consumes: - application/json definitions: viewBox: type: object properties: x: type: integer format: int16 # y -> types don't match: expect map key string or int get: bool "y": type: integer format: int16 width: type: integer format: int16 height: type: integer format: int16 info: description: Test RESTful APIs title: Test Server version: 1.0.0 basePath: /api paths: /test: get: operationId: findAll parameters: - name: since in: query type: integer format: int64 - name: limit in: query type: integer format: int32 default: 20 responses: 200: description: Array[Trigger] schema: type: array items: $ref: "#/definitions/viewBox" produces: - application/json schemes: - https swagger: "2.0" ` const withYKey = `consumes: - application/json definitions: viewBox: type: object properties: x: type: integer format: int16 # y -> types don't match: expect map key string or int get: bool y: type: integer format: int16 width: type: integer format: int16 height: type: integer format: int16 info: description: Test RESTful APIs title: Test Server version: 1.0.0 basePath: /api paths: /test: get: operationId: findAll parameters: - name: since in: query type: integer format: int64 - name: limit in: query type: integer format: int32 default: 20 responses: 200: description: Array[Trigger] schema: type: array items: $ref: "#/definitions/viewBox" produces: - application/json schemes: - https swagger: "2.0" ` const yamlPetStore = `swagger: '2.0' info: version: '1.0.0' title: Swagger Petstore description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification termsOfService: http://helloreverb.com/terms/ contact: name: Swagger API team email: foo@example.com url: http://swagger.io license: name: MIT url: http://opensource.org/licenses/MIT host: petstore.swagger.wordnik.com basePath: /api schemes: - http consumes: - application/json produces: - application/json paths: /pets: get: description: Returns all pets from the system that the user has access to operationId: findPets produces: - application/json - application/xml - text/xml - text/html parameters: - name: tags in: query description: tags to filter by required: false type: array items: type: string collectionFormat: csv - name: limit in: query description: maximum number of results to return required: false type: integer format: int32 responses: '200': description: pet response schema: type: array items: $ref: '#/definitions/pet' default: description: unexpected error schema: $ref: '#/definitions/errorModel' post: description: Creates a new pet in the store. Duplicates are allowed operationId: addPet produces: - application/json parameters: - name: pet in: body description: Pet to add to the store required: true schema: $ref: '#/definitions/newPet' responses: '200': description: pet response schema: $ref: '#/definitions/pet' default: description: unexpected error schema: $ref: '#/definitions/errorModel' /pets/{id}: get: description: Returns a user based on a single ID, if the user does not have access to the pet operationId: findPetById produces: - application/json - application/xml - text/xml - text/html parameters: - name: id in: path description: ID of pet to fetch required: true type: integer format: int64 responses: '200': description: pet response schema: $ref: '#/definitions/pet' default: description: unexpected error schema: $ref: '#/definitions/errorModel' delete: description: deletes a single pet based on the ID supplied operationId: deletePet parameters: - name: id in: path description: ID of pet to delete required: true type: integer format: int64 responses: '204': description: pet deleted default: description: unexpected error schema: $ref: '#/definitions/errorModel' definitions: pet: required: - id - name properties: id: type: integer format: int64 name: type: string tag: type: string newPet: allOf: - $ref: '#/definitions/pet' - required: - name properties: id: type: integer format: int64 name: type: string errorModel: required: - code - message properties: code: type: integer format: int32 message: type: string `