mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Added missing mysql driver package dependency
This commit is contained in:
parent
3226a3a58e
commit
18ff1569b9
15
Godeps/Godeps.json
generated
15
Godeps/Godeps.json
generated
@ -19,6 +19,11 @@
|
||||
"Comment": "1.2.0-38-g9908e96",
|
||||
"Rev": "9908e96513e5a94de37004098a3974a567f18111"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
"Comment": "v1.2-26-g9543750",
|
||||
"Rev": "9543750295406ef070f7de8ae9c43ccddd44e15e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-xorm/core",
|
||||
"Rev": "a949e067ced1cb6e6ef5c38b6f28b074fa718f1e"
|
||||
@ -37,13 +42,17 @@
|
||||
"Rev": "d10e2c8f62100097910367dee90a9bd89d426a44"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/smartystreets/goconvey/convey",
|
||||
"Comment": "1.5.0-254-g627707e",
|
||||
"Rev": "627707e8db4a4e52f4e1fbbb4e10d98e79a3c946"
|
||||
"ImportPath": "golang.org/x/net/context",
|
||||
"Rev": "972f0c5fbe4ae29e666c3f78c3ed42ae7a448b0a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/oauth2",
|
||||
"Rev": "e5909d4679a1926c774c712b343f10b8298687a3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/ini.v1",
|
||||
"Comment": "v0-10-g28ad8c4",
|
||||
"Rev": "28ad8c408ba20e5c86b06d64cd2cc9248f640a83"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
8
Godeps/_workspace/src/github.com/go-sql-driver/mysql/.gitignore
generated
vendored
Normal file
8
Godeps/_workspace/src/github.com/go-sql-driver/mysql/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
Icon?
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
9
Godeps/_workspace/src/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/go-sql-driver/mysql/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- tip
|
||||
|
||||
before_script:
|
||||
- mysql -e 'create database gotest;'
|
36
Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
Normal file
36
Godeps/_workspace/src/github.com/go-sql-driver/mysql/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
# This is the official list of Go-MySQL-Driver authors for copyright purposes.
|
||||
|
||||
# If you are submitting a patch, please add your name or the name of the
|
||||
# organization which holds the copyright to this list in alphabetical order.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name <email address>
|
||||
# The email address is not required for organizations.
|
||||
# Please keep the list sorted.
|
||||
|
||||
|
||||
# Individual Persons
|
||||
|
||||
Aaron Hopkins <go-sql-driver at die.net>
|
||||
Arne Hormann <arnehormann at gmail.com>
|
||||
Carlos Nieto <jose.carlos at menteslibres.net>
|
||||
DisposaBoy <disposaboy at dby.me>
|
||||
Frederick Mayle <frederickmayle at gmail.com>
|
||||
Gustavo Kristic <gkristic at gmail.com>
|
||||
Hanno Braun <mail at hannobraun.com>
|
||||
Henri Yandell <flamefew at gmail.com>
|
||||
James Harr <james.harr at gmail.com>
|
||||
Jian Zhen <zhenjl at gmail.com>
|
||||
Julien Schmidt <go-sql-driver at julienschmidt.com>
|
||||
Leonardo YongUk Kim <dalinaum at gmail.com>
|
||||
Lucas Liu <extrafliu at gmail.com>
|
||||
Luke Scott <luke at webconnex.com>
|
||||
Michael Woolnough <michael.woolnough at gmail.com>
|
||||
Nicola Peduzzi <thenikso at gmail.com>
|
||||
Xiaobing Jiang <s7v7nislands at gmail.com>
|
||||
Xiuming Chen <cc at cxm.cc>
|
||||
|
||||
# Organizations
|
||||
|
||||
Barracuda Networks, Inc.
|
||||
Google Inc.
|
83
Godeps/_workspace/src/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
Normal file
83
Godeps/_workspace/src/github.com/go-sql-driver/mysql/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
## HEAD
|
||||
|
||||
Changes:
|
||||
|
||||
- Use decimals field from MySQL to format time types
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Enable microsecond resolution on TIME, DATETIME and TIMESTAMP
|
||||
|
||||
|
||||
## Version 1.2 (2014-06-03)
|
||||
|
||||
Changes:
|
||||
|
||||
- We switched back to a "rolling release". `go get` installs the current master branch again
|
||||
- Version v1 of the driver will not be maintained anymore. Go 1.0 is no longer supported by this driver
|
||||
- Exported errors to allow easy checking from application code
|
||||
- Enabled TCP Keepalives on TCP connections
|
||||
- Optimized INFILE handling (better buffer size calculation, lazy init, ...)
|
||||
- The DSN parser also checks for a missing separating slash
|
||||
- Faster binary date / datetime to string formatting
|
||||
- Also exported the MySQLWarning type
|
||||
- mysqlConn.Close returns the first error encountered instead of ignoring all errors
|
||||
- writePacket() automatically writes the packet size to the header
|
||||
- readPacket() uses an iterative approach instead of the recursive approach to merge splitted packets
|
||||
|
||||
New Features:
|
||||
|
||||
- `RegisterDial` allows the usage of a custom dial function to establish the network connection
|
||||
- Setting the connection collation is possible with the `collation` DSN parameter. This parameter should be preferred over the `charset` parameter
|
||||
- Logging of critical errors is configurable with `SetLogger`
|
||||
- Google CloudSQL support
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Allow more than 32 parameters in prepared statements
|
||||
- Various old_password fixes
|
||||
- Fixed TestConcurrent test to pass Go's race detection
|
||||
- Fixed appendLengthEncodedInteger for large numbers
|
||||
- Renamed readLengthEnodedString to readLengthEncodedString and skipLengthEnodedString to skipLengthEncodedString (fixed typo)
|
||||
|
||||
|
||||
## Version 1.1 (2013-11-02)
|
||||
|
||||
Changes:
|
||||
|
||||
- Go-MySQL-Driver now requires Go 1.1
|
||||
- Connections now use the collation `utf8_general_ci` by default. Adding `&charset=UTF8` to the DSN should not be necessary anymore
|
||||
- Made closing rows and connections error tolerant. This allows for example deferring rows.Close() without checking for errors
|
||||
- `[]byte(nil)` is now treated as a NULL value. Before, it was treated like an empty string / `[]byte("")`
|
||||
- DSN parameter values must now be url.QueryEscape'ed. This allows text values to contain special characters, such as '&'.
|
||||
- Use the IO buffer also for writing. This results in zero allocations (by the driver) for most queries
|
||||
- Optimized the buffer for reading
|
||||
- stmt.Query now caches column metadata
|
||||
- New Logo
|
||||
- Changed the copyright header to include all contributors
|
||||
- Improved the LOAD INFILE documentation
|
||||
- The driver struct is now exported to make the driver directly accessible
|
||||
- Refactored the driver tests
|
||||
- Added more benchmarks and moved all to a separate file
|
||||
- Other small refactoring
|
||||
|
||||
New Features:
|
||||
|
||||
- Added *old_passwords* support: Required in some cases, but must be enabled by adding `allowOldPasswords=true` to the DSN since it is insecure
|
||||
- Added a `clientFoundRows` parameter: Return the number of matching rows instead of the number of rows changed on UPDATEs
|
||||
- Added TLS/SSL support: Use a TLS/SSL encrypted connection to the server. Custom TLS configs can be registered and used
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fixed MySQL 4.1 support: MySQL 4.1 sends packets with lengths which differ from the specification
|
||||
- Convert to DB timezone when inserting `time.Time`
|
||||
- Splitted packets (more than 16MB) are now merged correctly
|
||||
- Fixed false positive `io.EOF` errors when the data was fully read
|
||||
- Avoid panics on reuse of closed connections
|
||||
- Fixed empty string producing false nil values
|
||||
- Fixed sign byte for positive TIME fields
|
||||
|
||||
|
||||
## Version 1.0 (2013-05-14)
|
||||
|
||||
Initial Release
|
40
Godeps/_workspace/src/github.com/go-sql-driver/mysql/CONTRIBUTING.md
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/go-sql-driver/mysql/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed).
|
||||
|
||||
Please provide the following minimum information:
|
||||
* Your Go-MySQL-Driver version (or git SHA)
|
||||
* Your Go version (run `go version` in your console)
|
||||
* A detailed issue description
|
||||
* Error Log if present
|
||||
* If possible, a short example
|
||||
|
||||
|
||||
## Contributing Code
|
||||
|
||||
By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file.
|
||||
Don't forget to add yourself to the AUTHORS file.
|
||||
|
||||
### Pull Requests Checklist
|
||||
|
||||
Please check the following points before submitting your pull request:
|
||||
- [x] Code compiles correctly
|
||||
- [x] Created tests, if possible
|
||||
- [x] All tests pass
|
||||
- [x] Extended the README / documentation, if necessary
|
||||
- [x] Added yourself to the AUTHORS file
|
||||
|
||||
### Code Review
|
||||
|
||||
Everyone is invited to review and comment on pull requests.
|
||||
If it looks fine to you, comment with "LGTM" (Looks good to me).
|
||||
|
||||
If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes.
|
||||
|
||||
Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM".
|
||||
|
||||
## Development Ideas
|
||||
|
||||
If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page.
|
373
Godeps/_workspace/src/github.com/go-sql-driver/mysql/LICENSE
generated
vendored
Normal file
373
Godeps/_workspace/src/github.com/go-sql-driver/mysql/LICENSE
generated
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
346
Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md
generated
vendored
Normal file
346
Godeps/_workspace/src/github.com/go-sql-driver/mysql/README.md
generated
vendored
Normal file
@ -0,0 +1,346 @@
|
||||
# Go-MySQL-Driver
|
||||
|
||||
A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) package
|
||||
|
||||

|
||||
|
||||
**Latest stable Release:** [Version 1.2 (June 03, 2014)](https://github.com/go-sql-driver/mysql/releases)
|
||||
|
||||
[](https://travis-ci.org/go-sql-driver/mysql)
|
||||
|
||||
---------------------------------------
|
||||
* [Features](#features)
|
||||
* [Requirements](#requirements)
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [DSN (Data Source Name)](#dsn-data-source-name)
|
||||
* [Password](#password)
|
||||
* [Protocol](#protocol)
|
||||
* [Address](#address)
|
||||
* [Parameters](#parameters)
|
||||
* [Examples](#examples)
|
||||
* [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)
|
||||
* [time.Time support](#timetime-support)
|
||||
* [Unicode support](#unicode-support)
|
||||
* [Testing / Development](#testing--development)
|
||||
* [License](#license)
|
||||
|
||||
---------------------------------------
|
||||
|
||||
## Features
|
||||
* Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance")
|
||||
* Native Go implementation. No C-bindings, just pure Go
|
||||
* Connections over TCP/IPv4, TCP/IPv6 or Unix domain sockets
|
||||
* Automatic handling of broken connections
|
||||
* Automatic Connection Pooling *(by database/sql package)*
|
||||
* Supports queries larger than 16MB
|
||||
* Full [`sql.RawBytes`](http://golang.org/pkg/database/sql/#RawBytes) support.
|
||||
* Intelligent `LONG DATA` handling in prepared statements
|
||||
* Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support
|
||||
* Optional `time.Time` parsing
|
||||
|
||||
## Requirements
|
||||
* Go 1.1 or higher
|
||||
* MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
|
||||
|
||||
---------------------------------------
|
||||
|
||||
## Installation
|
||||
Simple install the package to your [$GOPATH](http://code.google.com/p/go-wiki/wiki/GOPATH "GOPATH") with the [go tool](http://golang.org/cmd/go/ "go command") from shell:
|
||||
```bash
|
||||
$ go get github.com/go-sql-driver/mysql
|
||||
```
|
||||
Make sure [Git is installed](http://git-scm.com/downloads) on your machine and in your system's `PATH`.
|
||||
|
||||
## Usage
|
||||
_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](http://golang.org/pkg/database/sql) API then.
|
||||
|
||||
Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`:
|
||||
```go
|
||||
import "database/sql"
|
||||
import _ "github.com/go-sql-driver/mysql"
|
||||
|
||||
db, err := sql.Open("mysql", "user:password@/dbname")
|
||||
```
|
||||
|
||||
[Examples are available in our Wiki](https://github.com/go-sql-driver/mysql/wiki/Examples "Go-MySQL-Driver Examples").
|
||||
|
||||
|
||||
### DSN (Data Source Name)
|
||||
|
||||
The Data Source Name has a common format, like e.g. [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php) uses it, but without type-prefix (optional parts marked by squared brackets):
|
||||
```
|
||||
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]
|
||||
```
|
||||
|
||||
A DSN in its fullest form:
|
||||
```
|
||||
username:password@protocol(address)/dbname?param=value
|
||||
```
|
||||
|
||||
Except for the databasename, all values are optional. So the minimal DSN is:
|
||||
```
|
||||
/dbname
|
||||
```
|
||||
|
||||
If you do not want to preselect a database, leave `dbname` empty:
|
||||
```
|
||||
/
|
||||
```
|
||||
This has the same effect as an empty DSN string:
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
#### Password
|
||||
Passwords can consist of any character. Escaping is **not** necessary.
|
||||
|
||||
#### Protocol
|
||||
See [net.Dial](http://golang.org/pkg/net/#Dial) for more information which networks are available.
|
||||
In general you should use an Unix domain socket if available and TCP otherwise for best performance.
|
||||
|
||||
#### Address
|
||||
For TCP and UDP networks, addresses have the form `host:port`.
|
||||
If `host` is a literal IPv6 address, it must be enclosed in square brackets.
|
||||
The functions [net.JoinHostPort](http://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](http://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
|
||||
|
||||
For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`.
|
||||
|
||||
#### Parameters
|
||||
*Parameters are case-sensitive!*
|
||||
|
||||
Notice that any of `true`, `TRUE`, `True` or `1` is accepted to stand for a true boolean value. Not surprisingly, false can be specified as any of: `false`, `FALSE`, `False` or `0`.
|
||||
|
||||
##### `allowAllFiles`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`allowAllFiles=true` disables the file Whitelist for `LOAD DATA LOCAL INFILE` and allows *all* files.
|
||||
[*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)
|
||||
|
||||
##### `allowOldPasswords`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
`allowOldPasswords=true` allows the usage of the insecure old password method. This should be avoided, but is necessary in some cases. See also [the old_passwords wiki page](https://github.com/go-sql-driver/mysql/wiki/old_passwords).
|
||||
|
||||
##### `charset`
|
||||
|
||||
```
|
||||
Type: string
|
||||
Valid Values: <name>
|
||||
Default: none
|
||||
```
|
||||
|
||||
Sets the charset used for client-server interaction (`"SET NAMES <value>"`). If multiple charsets are set (separated by a comma), the following charset is used if setting the charset failes. This enables for example support for `utf8mb4` ([introduced in MySQL 5.5.3](http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html)) with fallback to `utf8` for older servers (`charset=utf8mb4,utf8`).
|
||||
|
||||
Usage of the `charset` parameter is discouraged because it issues additional queries to the server.
|
||||
Unless you need the fallback behavior, please use `collation` instead.
|
||||
|
||||
##### `collation`
|
||||
|
||||
```
|
||||
Type: string
|
||||
Valid Values: <name>
|
||||
Default: utf8_general_ci
|
||||
```
|
||||
|
||||
Sets the collation used for client-server interaction on connection. In contrast to `charset`, `collation` does not issue additional queries. If the specified collation is unavailable on the target server, the connection will fail.
|
||||
|
||||
A list of valid charsets for a server is retrievable with `SHOW COLLATION`.
|
||||
|
||||
##### `clientFoundRows`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`clientFoundRows=true` causes an UPDATE to return the number of matching rows instead of the number of rows changed.
|
||||
|
||||
|
||||
##### `loc`
|
||||
|
||||
```
|
||||
Type: string
|
||||
Valid Values: <escaped name>
|
||||
Default: UTC
|
||||
```
|
||||
|
||||
Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](http://golang.org/pkg/time/#LoadLocation) for details.
|
||||
|
||||
Please keep in mind, that param values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`.
|
||||
|
||||
|
||||
##### `parseTime`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`parseTime=true` changes the output type of `DATE` and `DATETIME` values to `time.Time` instead of `[]byte` / `string`
|
||||
|
||||
|
||||
##### `strict`
|
||||
|
||||
```
|
||||
Type: bool
|
||||
Valid Values: true, false
|
||||
Default: false
|
||||
```
|
||||
|
||||
`strict=true` enables the strict mode in which MySQL warnings are treated as errors.
|
||||
|
||||
By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes. See the [examples](#examples) for an DSN example.
|
||||
|
||||
|
||||
##### `timeout`
|
||||
|
||||
```
|
||||
Type: decimal number
|
||||
Default: OS default
|
||||
```
|
||||
|
||||
*Driver* side connection timeout. The value must be a string of decimal numbers, each with optional fraction and a unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout).
|
||||
|
||||
|
||||
##### `tls`
|
||||
|
||||
```
|
||||
Type: bool / string
|
||||
Valid Values: true, false, skip-verify, <name>
|
||||
Default: false
|
||||
```
|
||||
|
||||
`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](http://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
|
||||
|
||||
|
||||
##### System Variables
|
||||
|
||||
All other parameters are interpreted as system variables:
|
||||
* `autocommit`: `"SET autocommit=<value>"`
|
||||
* `time_zone`: `"SET time_zone=<value>"`
|
||||
* [`tx_isolation`](https://dev.mysql.com/doc/refman/5.5/en/server-system-variables.html#sysvar_tx_isolation): `"SET tx_isolation=<value>"`
|
||||
* `param`: `"SET <param>=<value>"`
|
||||
|
||||
*The values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!*
|
||||
|
||||
#### Examples
|
||||
```
|
||||
user@unix(/path/to/socket)/dbname
|
||||
```
|
||||
|
||||
```
|
||||
root:pw@unix(/tmp/mysql.sock)/myDatabase?loc=Local
|
||||
```
|
||||
|
||||
```
|
||||
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
|
||||
```
|
||||
|
||||
Use the [strict mode](#strict) but ignore notes:
|
||||
```
|
||||
user:password@/dbname?strict=true&sql_notes=false
|
||||
```
|
||||
|
||||
TCP via IPv6:
|
||||
```
|
||||
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname?timeout=90s&collation=utf8mb4_unicode_ci
|
||||
```
|
||||
|
||||
TCP on a remote host, e.g. Amazon RDS:
|
||||
```
|
||||
id:password@tcp(your-amazonaws-uri.com:3306)/dbname
|
||||
```
|
||||
|
||||
Google Cloud SQL on App Engine:
|
||||
```
|
||||
user@cloudsql(project-id:instance-name)/dbname
|
||||
```
|
||||
|
||||
TCP using default port (3306) on localhost:
|
||||
```
|
||||
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
|
||||
```
|
||||
|
||||
Use the default protocol (tcp) and host (localhost:3306):
|
||||
```
|
||||
user:password@/dbname
|
||||
```
|
||||
|
||||
No Database preselected:
|
||||
```
|
||||
user:password@/
|
||||
```
|
||||
|
||||
### `LOAD DATA LOCAL INFILE` support
|
||||
For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
|
||||
```go
|
||||
import "github.com/go-sql-driver/mysql"
|
||||
```
|
||||
|
||||
Files must be whitelisted by registering them with `mysql.RegisterLocalFile(filepath)` (recommended) or the Whitelist check must be deactivated by using the DSN parameter `allowAllFiles=true` ([*Might be insecure!*](http://dev.mysql.com/doc/refman/5.7/en/load-data-local.html)).
|
||||
|
||||
To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::<name>` then.
|
||||
|
||||
See the [godoc of Go-MySQL-Driver](http://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details.
|
||||
|
||||
|
||||
### `time.Time` support
|
||||
The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm.
|
||||
|
||||
However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](http://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
|
||||
|
||||
**Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes).
|
||||
|
||||
Alternatively you can use the [`NullTime`](http://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`.
|
||||
|
||||
|
||||
### Unicode support
|
||||
Since version 1.1 Go-MySQL-Driver automatically uses the collation `utf8_general_ci` by default.
|
||||
|
||||
Other collations / charsets can be set using the [`collation`](#collation) DSN parameter.
|
||||
|
||||
Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAMES utf8`) to the DSN to enable proper UTF-8 support. This is not necessary anymore. The [`collation`](#collation) parameter should be preferred to set another collation / charset than the default.
|
||||
|
||||
See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support.
|
||||
|
||||
|
||||
## Testing / Development
|
||||
To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details.
|
||||
|
||||
Go-MySQL-Driver is not feature-complete yet. Your help is very appreciated.
|
||||
If you want to contribute, you can work on an [open issue](https://github.com/go-sql-driver/mysql/issues?state=open) or review a [pull request](https://github.com/go-sql-driver/mysql/pulls).
|
||||
|
||||
See the [Contribution Guidelines](https://github.com/go-sql-driver/mysql/blob/master/CONTRIBUTING.md) for details.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
## License
|
||||
Go-MySQL-Driver is licensed under the [Mozilla Public License Version 2.0](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
|
||||
|
||||
Mozilla summarizes the license scope as follows:
|
||||
> MPL: The copyleft applies to any files containing MPLed code.
|
||||
|
||||
|
||||
That means:
|
||||
* You can **use** the **unchanged** source code both in private and commercially
|
||||
* When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0)
|
||||
* You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**
|
||||
|
||||
Please read the [MPL 2.0 FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) if you have further questions regarding the license.
|
||||
|
||||
You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
|
||||
|
||||

|
||||
|
19
Godeps/_workspace/src/github.com/go-sql-driver/mysql/appengine.go
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/go-sql-driver/mysql/appengine.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// +build appengine
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"appengine/cloudsql"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterDial("cloudsql", cloudsql.Dial)
|
||||
}
|
208
Godeps/_workspace/src/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
Normal file
208
Godeps/_workspace/src/github.com/go-sql-driver/mysql/benchmark_test.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type TB testing.B
|
||||
|
||||
func (tb *TB) check(err error) {
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB {
|
||||
tb.check(err)
|
||||
return db
|
||||
}
|
||||
|
||||
func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows {
|
||||
tb.check(err)
|
||||
return rows
|
||||
}
|
||||
|
||||
func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
|
||||
tb.check(err)
|
||||
return stmt
|
||||
}
|
||||
|
||||
func initDB(b *testing.B, queries ...string) *sql.DB {
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
for _, query := range queries {
|
||||
if _, err := db.Exec(query); err != nil {
|
||||
b.Fatalf("Error on %q: %v", query, err)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
const concurrencyLevel = 10
|
||||
|
||||
func BenchmarkQuery(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := initDB(b,
|
||||
"DROP TABLE IF EXISTS foo",
|
||||
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
|
||||
`INSERT INTO foo VALUES (1, "one")`,
|
||||
`INSERT INTO foo VALUES (2, "two")`,
|
||||
)
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
var got string
|
||||
tb.check(stmt.QueryRow(1).Scan(&got))
|
||||
if got != "one" {
|
||||
b.Errorf("query = %q; want one", got)
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExec(b *testing.B) {
|
||||
tb := (*TB)(b)
|
||||
b.StopTimer()
|
||||
b.ReportAllocs()
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
db.SetMaxIdleConns(concurrencyLevel)
|
||||
defer db.Close()
|
||||
|
||||
stmt := tb.checkStmt(db.Prepare("DO 1"))
|
||||
defer stmt.Close()
|
||||
|
||||
remain := int64(b.N)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(concurrencyLevel)
|
||||
defer wg.Wait()
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < concurrencyLevel; i++ {
|
||||
go func() {
|
||||
for {
|
||||
if atomic.AddInt64(&remain, -1) < 0 {
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := stmt.Exec(); err != nil {
|
||||
b.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// data, but no db writes
|
||||
var roundtripSample []byte
|
||||
|
||||
func initRoundtripBenchmarks() ([]byte, int, int) {
|
||||
if roundtripSample == nil {
|
||||
roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
|
||||
}
|
||||
return roundtripSample, 16, len(roundtripSample)
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripTxt(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
sampleString := string(sample)
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
b.StartTimer()
|
||||
var result string
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sampleString[0:length]
|
||||
rows := tb.checkRows(db.Query(`SELECT "` + test + `"`))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if result != test {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRoundtripBin(b *testing.B) {
|
||||
b.StopTimer()
|
||||
sample, min, max := initRoundtripBenchmarks()
|
||||
b.ReportAllocs()
|
||||
tb := (*TB)(b)
|
||||
db := tb.checkDB(sql.Open("mysql", dsn))
|
||||
defer db.Close()
|
||||
stmt := tb.checkStmt(db.Prepare("SELECT ?"))
|
||||
defer stmt.Close()
|
||||
b.StartTimer()
|
||||
var result sql.RawBytes
|
||||
for i := 0; i < b.N; i++ {
|
||||
length := min + i
|
||||
if length > max {
|
||||
length = max
|
||||
}
|
||||
test := sample[0:length]
|
||||
rows := tb.checkRows(stmt.Query(test))
|
||||
if !rows.Next() {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
err := rows.Scan(&result)
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
b.Fatalf("crashed")
|
||||
}
|
||||
if !bytes.Equal(result, test) {
|
||||
rows.Close()
|
||||
b.Errorf("mismatch")
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
}
|
136
Godeps/_workspace/src/github.com/go-sql-driver/mysql/buffer.go
generated
vendored
Normal file
136
Godeps/_workspace/src/github.com/go-sql-driver/mysql/buffer.go
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import "io"
|
||||
|
||||
const defaultBufSize = 4096
|
||||
|
||||
// A buffer which is used for both reading and writing.
|
||||
// This is possible since communication on each connection is synchronous.
|
||||
// In other words, we can't write and read simultaneously on the same connection.
|
||||
// The buffer is similar to bufio.Reader / Writer but zero-copy-ish
|
||||
// Also highly optimized for this particular use case.
|
||||
type buffer struct {
|
||||
buf []byte
|
||||
rd io.Reader
|
||||
idx int
|
||||
length int
|
||||
}
|
||||
|
||||
func newBuffer(rd io.Reader) buffer {
|
||||
var b [defaultBufSize]byte
|
||||
return buffer{
|
||||
buf: b[:],
|
||||
rd: rd,
|
||||
}
|
||||
}
|
||||
|
||||
// fill reads into the buffer until at least _need_ bytes are in it
|
||||
func (b *buffer) fill(need int) error {
|
||||
n := b.length
|
||||
|
||||
// move existing data to the beginning
|
||||
if n > 0 && b.idx > 0 {
|
||||
copy(b.buf[0:n], b.buf[b.idx:])
|
||||
}
|
||||
|
||||
// grow buffer if necessary
|
||||
// TODO: let the buffer shrink again at some point
|
||||
// Maybe keep the org buf slice and swap back?
|
||||
if need > len(b.buf) {
|
||||
// Round up to the next multiple of the default size
|
||||
newBuf := make([]byte, ((need/defaultBufSize)+1)*defaultBufSize)
|
||||
copy(newBuf, b.buf)
|
||||
b.buf = newBuf
|
||||
}
|
||||
|
||||
b.idx = 0
|
||||
|
||||
for {
|
||||
nn, err := b.rd.Read(b.buf[n:])
|
||||
n += nn
|
||||
|
||||
switch err {
|
||||
case nil:
|
||||
if n < need {
|
||||
continue
|
||||
}
|
||||
b.length = n
|
||||
return nil
|
||||
|
||||
case io.EOF:
|
||||
if n >= need {
|
||||
b.length = n
|
||||
return nil
|
||||
}
|
||||
return io.ErrUnexpectedEOF
|
||||
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns next N bytes from buffer.
|
||||
// The returned slice is only guaranteed to be valid until the next read
|
||||
func (b *buffer) readNext(need int) ([]byte, error) {
|
||||
if b.length < need {
|
||||
// refill
|
||||
if err := b.fill(need); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
offset := b.idx
|
||||
b.idx += need
|
||||
b.length -= need
|
||||
return b.buf[offset:b.idx], nil
|
||||
}
|
||||
|
||||
// returns a buffer with the requested size.
|
||||
// If possible, a slice from the existing buffer is returned.
|
||||
// Otherwise a bigger buffer is made.
|
||||
// Only one buffer (total) can be used at a time.
|
||||
func (b *buffer) takeBuffer(length int) []byte {
|
||||
if b.length > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// test (cheap) general case first
|
||||
if length <= defaultBufSize || length <= cap(b.buf) {
|
||||
return b.buf[:length]
|
||||
}
|
||||
|
||||
if length < maxPacketSize {
|
||||
b.buf = make([]byte, length)
|
||||
return b.buf
|
||||
}
|
||||
return make([]byte, length)
|
||||
}
|
||||
|
||||
// shortcut which can be used if the requested buffer is guaranteed to be
|
||||
// smaller than defaultBufSize
|
||||
// Only one buffer (total) can be used at a time.
|
||||
func (b *buffer) takeSmallBuffer(length int) []byte {
|
||||
if b.length == 0 {
|
||||
return b.buf[:length]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// takeCompleteBuffer returns the complete existing buffer.
|
||||
// This can be used if the necessary buffer size is unknown.
|
||||
// Only one buffer (total) can be used at a time.
|
||||
func (b *buffer) takeCompleteBuffer() []byte {
|
||||
if b.length == 0 {
|
||||
return b.buf
|
||||
}
|
||||
return nil
|
||||
}
|
236
Godeps/_workspace/src/github.com/go-sql-driver/mysql/collations.go
generated
vendored
Normal file
236
Godeps/_workspace/src/github.com/go-sql-driver/mysql/collations.go
generated
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2014 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
const defaultCollation byte = 33 // utf8_general_ci
|
||||
|
||||
// A list of available collations mapped to the internal ID.
|
||||
// To update this map use the following MySQL query:
|
||||
// SELECT COLLATION_NAME, ID FROM information_schema.COLLATIONS
|
||||
var collations = map[string]byte{
|
||||
"big5_chinese_ci": 1,
|
||||
"latin2_czech_cs": 2,
|
||||
"dec8_swedish_ci": 3,
|
||||
"cp850_general_ci": 4,
|
||||
"latin1_german1_ci": 5,
|
||||
"hp8_english_ci": 6,
|
||||
"koi8r_general_ci": 7,
|
||||
"latin1_swedish_ci": 8,
|
||||
"latin2_general_ci": 9,
|
||||
"swe7_swedish_ci": 10,
|
||||
"ascii_general_ci": 11,
|
||||
"ujis_japanese_ci": 12,
|
||||
"sjis_japanese_ci": 13,
|
||||
"cp1251_bulgarian_ci": 14,
|
||||
"latin1_danish_ci": 15,
|
||||
"hebrew_general_ci": 16,
|
||||
"tis620_thai_ci": 18,
|
||||
"euckr_korean_ci": 19,
|
||||
"latin7_estonian_cs": 20,
|
||||
"latin2_hungarian_ci": 21,
|
||||
"koi8u_general_ci": 22,
|
||||
"cp1251_ukrainian_ci": 23,
|
||||
"gb2312_chinese_ci": 24,
|
||||
"greek_general_ci": 25,
|
||||
"cp1250_general_ci": 26,
|
||||
"latin2_croatian_ci": 27,
|
||||
"gbk_chinese_ci": 28,
|
||||
"cp1257_lithuanian_ci": 29,
|
||||
"latin5_turkish_ci": 30,
|
||||
"latin1_german2_ci": 31,
|
||||
"armscii8_general_ci": 32,
|
||||
"utf8_general_ci": 33,
|
||||
"cp1250_czech_cs": 34,
|
||||
"ucs2_general_ci": 35,
|
||||
"cp866_general_ci": 36,
|
||||
"keybcs2_general_ci": 37,
|
||||
"macce_general_ci": 38,
|
||||
"macroman_general_ci": 39,
|
||||
"cp852_general_ci": 40,
|
||||
"latin7_general_ci": 41,
|
||||
"latin7_general_cs": 42,
|
||||
"macce_bin": 43,
|
||||
"cp1250_croatian_ci": 44,
|
||||
"utf8mb4_general_ci": 45,
|
||||
"utf8mb4_bin": 46,
|
||||
"latin1_bin": 47,
|
||||
"latin1_general_ci": 48,
|
||||
"latin1_general_cs": 49,
|
||||
"cp1251_bin": 50,
|
||||
"cp1251_general_ci": 51,
|
||||
"cp1251_general_cs": 52,
|
||||
"macroman_bin": 53,
|
||||
"utf16_general_ci": 54,
|
||||
"utf16_bin": 55,
|
||||
"utf16le_general_ci": 56,
|
||||
"cp1256_general_ci": 57,
|
||||
"cp1257_bin": 58,
|
||||
"cp1257_general_ci": 59,
|
||||
"utf32_general_ci": 60,
|
||||
"utf32_bin": 61,
|
||||
"utf16le_bin": 62,
|
||||
"binary": 63,
|
||||
"armscii8_bin": 64,
|
||||
"ascii_bin": 65,
|
||||
"cp1250_bin": 66,
|
||||
"cp1256_bin": 67,
|
||||
"cp866_bin": 68,
|
||||
"dec8_bin": 69,
|
||||
"greek_bin": 70,
|
||||
"hebrew_bin": 71,
|
||||
"hp8_bin": 72,
|
||||
"keybcs2_bin": 73,
|
||||
"koi8r_bin": 74,
|
||||
"koi8u_bin": 75,
|
||||
"latin2_bin": 77,
|
||||
"latin5_bin": 78,
|
||||
"latin7_bin": 79,
|
||||
"cp850_bin": 80,
|
||||
"cp852_bin": 81,
|
||||
"swe7_bin": 82,
|
||||
"utf8_bin": 83,
|
||||
"big5_bin": 84,
|
||||
"euckr_bin": 85,
|
||||
"gb2312_bin": 86,
|
||||
"gbk_bin": 87,
|
||||
"sjis_bin": 88,
|
||||
"tis620_bin": 89,
|
||||
"ucs2_bin": 90,
|
||||
"ujis_bin": 91,
|
||||
"geostd8_general_ci": 92,
|
||||
"geostd8_bin": 93,
|
||||
"latin1_spanish_ci": 94,
|
||||
"cp932_japanese_ci": 95,
|
||||
"cp932_bin": 96,
|
||||
"eucjpms_japanese_ci": 97,
|
||||
"eucjpms_bin": 98,
|
||||
"cp1250_polish_ci": 99,
|
||||
"utf16_unicode_ci": 101,
|
||||
"utf16_icelandic_ci": 102,
|
||||
"utf16_latvian_ci": 103,
|
||||
"utf16_romanian_ci": 104,
|
||||
"utf16_slovenian_ci": 105,
|
||||
"utf16_polish_ci": 106,
|
||||
"utf16_estonian_ci": 107,
|
||||
"utf16_spanish_ci": 108,
|
||||
"utf16_swedish_ci": 109,
|
||||
"utf16_turkish_ci": 110,
|
||||
"utf16_czech_ci": 111,
|
||||
"utf16_danish_ci": 112,
|
||||
"utf16_lithuanian_ci": 113,
|
||||
"utf16_slovak_ci": 114,
|
||||
"utf16_spanish2_ci": 115,
|
||||
"utf16_roman_ci": 116,
|
||||
"utf16_persian_ci": 117,
|
||||
"utf16_esperanto_ci": 118,
|
||||
"utf16_hungarian_ci": 119,
|
||||
"utf16_sinhala_ci": 120,
|
||||
"utf16_german2_ci": 121,
|
||||
"utf16_croatian_ci": 122,
|
||||
"utf16_unicode_520_ci": 123,
|
||||
"utf16_vietnamese_ci": 124,
|
||||
"ucs2_unicode_ci": 128,
|
||||
"ucs2_icelandic_ci": 129,
|
||||
"ucs2_latvian_ci": 130,
|
||||
"ucs2_romanian_ci": 131,
|
||||
"ucs2_slovenian_ci": 132,
|
||||
"ucs2_polish_ci": 133,
|
||||
"ucs2_estonian_ci": 134,
|
||||
"ucs2_spanish_ci": 135,
|
||||
"ucs2_swedish_ci": 136,
|
||||
"ucs2_turkish_ci": 137,
|
||||
"ucs2_czech_ci": 138,
|
||||
"ucs2_danish_ci": 139,
|
||||
"ucs2_lithuanian_ci": 140,
|
||||
"ucs2_slovak_ci": 141,
|
||||
"ucs2_spanish2_ci": 142,
|
||||
"ucs2_roman_ci": 143,
|
||||
"ucs2_persian_ci": 144,
|
||||
"ucs2_esperanto_ci": 145,
|
||||
"ucs2_hungarian_ci": 146,
|
||||
"ucs2_sinhala_ci": 147,
|
||||
"ucs2_german2_ci": 148,
|
||||
"ucs2_croatian_ci": 149,
|
||||
"ucs2_unicode_520_ci": 150,
|
||||
"ucs2_vietnamese_ci": 151,
|
||||
"ucs2_general_mysql500_ci": 159,
|
||||
"utf32_unicode_ci": 160,
|
||||
"utf32_icelandic_ci": 161,
|
||||
"utf32_latvian_ci": 162,
|
||||
"utf32_romanian_ci": 163,
|
||||
"utf32_slovenian_ci": 164,
|
||||
"utf32_polish_ci": 165,
|
||||
"utf32_estonian_ci": 166,
|
||||
"utf32_spanish_ci": 167,
|
||||
"utf32_swedish_ci": 168,
|
||||
"utf32_turkish_ci": 169,
|
||||
"utf32_czech_ci": 170,
|
||||
"utf32_danish_ci": 171,
|
||||
"utf32_lithuanian_ci": 172,
|
||||
"utf32_slovak_ci": 173,
|
||||
"utf32_spanish2_ci": 174,
|
||||
"utf32_roman_ci": 175,
|
||||
"utf32_persian_ci": 176,
|
||||
"utf32_esperanto_ci": 177,
|
||||
"utf32_hungarian_ci": 178,
|
||||
"utf32_sinhala_ci": 179,
|
||||
"utf32_german2_ci": 180,
|
||||
"utf32_croatian_ci": 181,
|
||||
"utf32_unicode_520_ci": 182,
|
||||
"utf32_vietnamese_ci": 183,
|
||||
"utf8_unicode_ci": 192,
|
||||
"utf8_icelandic_ci": 193,
|
||||
"utf8_latvian_ci": 194,
|
||||
"utf8_romanian_ci": 195,
|
||||
"utf8_slovenian_ci": 196,
|
||||
"utf8_polish_ci": 197,
|
||||
"utf8_estonian_ci": 198,
|
||||
"utf8_spanish_ci": 199,
|
||||
"utf8_swedish_ci": 200,
|
||||
"utf8_turkish_ci": 201,
|
||||
"utf8_czech_ci": 202,
|
||||
"utf8_danish_ci": 203,
|
||||
"utf8_lithuanian_ci": 204,
|
||||
"utf8_slovak_ci": 205,
|
||||
"utf8_spanish2_ci": 206,
|
||||
"utf8_roman_ci": 207,
|
||||
"utf8_persian_ci": 208,
|
||||
"utf8_esperanto_ci": 209,
|
||||
"utf8_hungarian_ci": 210,
|
||||
"utf8_sinhala_ci": 211,
|
||||
"utf8_german2_ci": 212,
|
||||
"utf8_croatian_ci": 213,
|
||||
"utf8_unicode_520_ci": 214,
|
||||
"utf8_vietnamese_ci": 215,
|
||||
"utf8_general_mysql500_ci": 223,
|
||||
"utf8mb4_unicode_ci": 224,
|
||||
"utf8mb4_icelandic_ci": 225,
|
||||
"utf8mb4_latvian_ci": 226,
|
||||
"utf8mb4_romanian_ci": 227,
|
||||
"utf8mb4_slovenian_ci": 228,
|
||||
"utf8mb4_polish_ci": 229,
|
||||
"utf8mb4_estonian_ci": 230,
|
||||
"utf8mb4_spanish_ci": 231,
|
||||
"utf8mb4_swedish_ci": 232,
|
||||
"utf8mb4_turkish_ci": 233,
|
||||
"utf8mb4_czech_ci": 234,
|
||||
"utf8mb4_danish_ci": 235,
|
||||
"utf8mb4_lithuanian_ci": 236,
|
||||
"utf8mb4_slovak_ci": 237,
|
||||
"utf8mb4_spanish2_ci": 238,
|
||||
"utf8mb4_roman_ci": 239,
|
||||
"utf8mb4_persian_ci": 240,
|
||||
"utf8mb4_esperanto_ci": 241,
|
||||
"utf8mb4_hungarian_ci": 242,
|
||||
"utf8mb4_sinhala_ci": 243,
|
||||
"utf8mb4_german2_ci": 244,
|
||||
"utf8mb4_croatian_ci": 245,
|
||||
"utf8mb4_unicode_520_ci": 246,
|
||||
"utf8mb4_vietnamese_ci": 247,
|
||||
}
|
268
Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go
generated
vendored
Normal file
268
Godeps/_workspace/src/github.com/go-sql-driver/mysql/connection.go
generated
vendored
Normal file
@ -0,0 +1,268 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type mysqlConn struct {
|
||||
buf buffer
|
||||
netConn net.Conn
|
||||
affectedRows uint64
|
||||
insertId uint64
|
||||
cfg *config
|
||||
maxPacketAllowed int
|
||||
maxWriteSize int
|
||||
flags clientFlag
|
||||
sequence uint8
|
||||
parseTime bool
|
||||
strict bool
|
||||
}
|
||||
|
||||
type config struct {
|
||||
user string
|
||||
passwd string
|
||||
net string
|
||||
addr string
|
||||
dbname string
|
||||
params map[string]string
|
||||
loc *time.Location
|
||||
tls *tls.Config
|
||||
timeout time.Duration
|
||||
collation uint8
|
||||
allowAllFiles bool
|
||||
allowOldPasswords bool
|
||||
clientFoundRows bool
|
||||
}
|
||||
|
||||
// Handles parameters set in DSN after the connection is established
|
||||
func (mc *mysqlConn) handleParams() (err error) {
|
||||
for param, val := range mc.cfg.params {
|
||||
switch param {
|
||||
// Charset
|
||||
case "charset":
|
||||
charsets := strings.Split(val, ",")
|
||||
for i := range charsets {
|
||||
// ignore errors here - a charset may not exist
|
||||
err = mc.exec("SET NAMES " + charsets[i])
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// time.Time parsing
|
||||
case "parseTime":
|
||||
var isBool bool
|
||||
mc.parseTime, isBool = readBool(val)
|
||||
if !isBool {
|
||||
return errors.New("Invalid Bool value: " + val)
|
||||
}
|
||||
|
||||
// Strict mode
|
||||
case "strict":
|
||||
var isBool bool
|
||||
mc.strict, isBool = readBool(val)
|
||||
if !isBool {
|
||||
return errors.New("Invalid Bool value: " + val)
|
||||
}
|
||||
|
||||
// Compression
|
||||
case "compress":
|
||||
err = errors.New("Compression not implemented yet")
|
||||
return
|
||||
|
||||
// System Vars
|
||||
default:
|
||||
err = mc.exec("SET " + param + "=" + val + "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Begin() (driver.Tx, error) {
|
||||
if mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
err := mc.exec("START TRANSACTION")
|
||||
if err == nil {
|
||||
return &mysqlTx{mc}, err
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Close() (err error) {
|
||||
// Makes Close idempotent
|
||||
if mc.netConn != nil {
|
||||
err = mc.writeCommandPacket(comQuit)
|
||||
if err == nil {
|
||||
err = mc.netConn.Close()
|
||||
} else {
|
||||
mc.netConn.Close()
|
||||
}
|
||||
mc.netConn = nil
|
||||
}
|
||||
|
||||
mc.cfg = nil
|
||||
mc.buf.rd = nil
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
|
||||
if mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
// Send command
|
||||
err := mc.writeCommandPacketStr(comStmtPrepare, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stmt := &mysqlStmt{
|
||||
mc: mc,
|
||||
}
|
||||
|
||||
// Read Result
|
||||
columnCount, err := stmt.readPrepareResultPacket()
|
||||
if err == nil {
|
||||
if stmt.paramCount > 0 {
|
||||
if err = mc.readUntilEOF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if columnCount > 0 {
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
}
|
||||
|
||||
return stmt, err
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
||||
if mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
if len(args) == 0 { // no args, fastpath
|
||||
mc.affectedRows = 0
|
||||
mc.insertId = 0
|
||||
|
||||
err := mc.exec(query)
|
||||
if err == nil {
|
||||
return &mysqlResult{
|
||||
affectedRows: int64(mc.affectedRows),
|
||||
insertId: int64(mc.insertId),
|
||||
}, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// with args, must use prepared stmt
|
||||
return nil, driver.ErrSkip
|
||||
|
||||
}
|
||||
|
||||
// Internal function to execute commands
|
||||
func (mc *mysqlConn) exec(query string) error {
|
||||
// Send command
|
||||
err := mc.writeCommandPacketStr(comQuery, query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err == nil && resLen > 0 {
|
||||
if err = mc.readUntilEOF(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||
if mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
if len(args) == 0 { // no args, fastpath
|
||||
// Send command
|
||||
err := mc.writeCommandPacketStr(comQuery, query)
|
||||
if err == nil {
|
||||
// Read Result
|
||||
var resLen int
|
||||
resLen, err = mc.readResultSetHeaderPacket()
|
||||
if err == nil {
|
||||
rows := new(textRows)
|
||||
rows.mc = mc
|
||||
|
||||
if resLen == 0 {
|
||||
// no columns, no more data
|
||||
return emptyRows{}, nil
|
||||
}
|
||||
// Columns
|
||||
rows.columns, err = mc.readColumns(resLen)
|
||||
return rows, err
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// with args, must use prepared stmt
|
||||
return nil, driver.ErrSkip
|
||||
}
|
||||
|
||||
// Gets the value of the given MySQL System Variable
|
||||
// The returned byte slice is only valid until the next read
|
||||
func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
|
||||
// Send command
|
||||
if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err == nil {
|
||||
rows := new(textRows)
|
||||
rows.mc = mc
|
||||
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
if err := mc.readUntilEOF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
dest := make([]driver.Value, resLen)
|
||||
if err = rows.readRow(dest); err == nil {
|
||||
return dest[0].([]byte), mc.readUntilEOF()
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
132
Godeps/_workspace/src/github.com/go-sql-driver/mysql/const.go
generated
vendored
Normal file
132
Godeps/_workspace/src/github.com/go-sql-driver/mysql/const.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
const (
|
||||
minProtocolVersion byte = 10
|
||||
maxPacketSize = 1<<24 - 1
|
||||
timeFormat = "2006-01-02 15:04:05.999999"
|
||||
)
|
||||
|
||||
// MySQL constants documentation:
|
||||
// http://dev.mysql.com/doc/internals/en/client-server-protocol.html
|
||||
|
||||
const (
|
||||
iOK byte = 0x00
|
||||
iLocalInFile byte = 0xfb
|
||||
iEOF byte = 0xfe
|
||||
iERR byte = 0xff
|
||||
)
|
||||
|
||||
type clientFlag uint32
|
||||
|
||||
const (
|
||||
clientLongPassword clientFlag = 1 << iota
|
||||
clientFoundRows
|
||||
clientLongFlag
|
||||
clientConnectWithDB
|
||||
clientNoSchema
|
||||
clientCompress
|
||||
clientODBC
|
||||
clientLocalFiles
|
||||
clientIgnoreSpace
|
||||
clientProtocol41
|
||||
clientInteractive
|
||||
clientSSL
|
||||
clientIgnoreSIGPIPE
|
||||
clientTransactions
|
||||
clientReserved
|
||||
clientSecureConn
|
||||
clientMultiStatements
|
||||
clientMultiResults
|
||||
)
|
||||
|
||||
const (
|
||||
comQuit byte = iota + 1
|
||||
comInitDB
|
||||
comQuery
|
||||
comFieldList
|
||||
comCreateDB
|
||||
comDropDB
|
||||
comRefresh
|
||||
comShutdown
|
||||
comStatistics
|
||||
comProcessInfo
|
||||
comConnect
|
||||
comProcessKill
|
||||
comDebug
|
||||
comPing
|
||||
comTime
|
||||
comDelayedInsert
|
||||
comChangeUser
|
||||
comBinlogDump
|
||||
comTableDump
|
||||
comConnectOut
|
||||
comRegiserSlave
|
||||
comStmtPrepare
|
||||
comStmtExecute
|
||||
comStmtSendLongData
|
||||
comStmtClose
|
||||
comStmtReset
|
||||
comSetOption
|
||||
comStmtFetch
|
||||
)
|
||||
|
||||
const (
|
||||
fieldTypeDecimal byte = iota
|
||||
fieldTypeTiny
|
||||
fieldTypeShort
|
||||
fieldTypeLong
|
||||
fieldTypeFloat
|
||||
fieldTypeDouble
|
||||
fieldTypeNULL
|
||||
fieldTypeTimestamp
|
||||
fieldTypeLongLong
|
||||
fieldTypeInt24
|
||||
fieldTypeDate
|
||||
fieldTypeTime
|
||||
fieldTypeDateTime
|
||||
fieldTypeYear
|
||||
fieldTypeNewDate
|
||||
fieldTypeVarChar
|
||||
fieldTypeBit
|
||||
)
|
||||
const (
|
||||
fieldTypeNewDecimal byte = iota + 0xf6
|
||||
fieldTypeEnum
|
||||
fieldTypeSet
|
||||
fieldTypeTinyBLOB
|
||||
fieldTypeMediumBLOB
|
||||
fieldTypeLongBLOB
|
||||
fieldTypeBLOB
|
||||
fieldTypeVarString
|
||||
fieldTypeString
|
||||
fieldTypeGeometry
|
||||
)
|
||||
|
||||
type fieldFlag uint16
|
||||
|
||||
const (
|
||||
flagNotNULL fieldFlag = 1 << iota
|
||||
flagPriKey
|
||||
flagUniqueKey
|
||||
flagMultipleKey
|
||||
flagBLOB
|
||||
flagUnsigned
|
||||
flagZeroFill
|
||||
flagBinary
|
||||
flagEnum
|
||||
flagAutoIncrement
|
||||
flagTimestamp
|
||||
flagSet
|
||||
flagUnknown1
|
||||
flagUnknown2
|
||||
flagUnknown3
|
||||
flagUnknown4
|
||||
)
|
138
Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go
generated
vendored
Normal file
138
Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// The driver should be used via the database/sql package:
|
||||
//
|
||||
// import "database/sql"
|
||||
// import _ "github.com/go-sql-driver/mysql"
|
||||
//
|
||||
// db, err := sql.Open("mysql", "user:password@/dbname")
|
||||
//
|
||||
// See https://github.com/go-sql-driver/mysql#usage for details
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"net"
|
||||
)
|
||||
|
||||
// This struct is exported to make the driver directly accessible.
|
||||
// In general the driver is used via the database/sql package.
|
||||
type MySQLDriver struct{}
|
||||
|
||||
// DialFunc is a function which can be used to establish the network connection.
|
||||
// Custom dial functions must be registered with RegisterDial
|
||||
type DialFunc func(addr string) (net.Conn, error)
|
||||
|
||||
var dials map[string]DialFunc
|
||||
|
||||
// RegisterDial registers a custom dial function. It can then be used by the
|
||||
// network address mynet(addr), where mynet is the registered new network.
|
||||
// addr is passed as a parameter to the dial function.
|
||||
func RegisterDial(net string, dial DialFunc) {
|
||||
if dials == nil {
|
||||
dials = make(map[string]DialFunc)
|
||||
}
|
||||
dials[net] = dial
|
||||
}
|
||||
|
||||
// Open new Connection.
|
||||
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
|
||||
// the DSN string is formated
|
||||
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||
var err error
|
||||
|
||||
// New mysqlConn
|
||||
mc := &mysqlConn{
|
||||
maxPacketAllowed: maxPacketSize,
|
||||
maxWriteSize: maxPacketSize - 1,
|
||||
}
|
||||
mc.cfg, err = parseDSN(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Connect to Server
|
||||
if dial, ok := dials[mc.cfg.net]; ok {
|
||||
mc.netConn, err = dial(mc.cfg.addr)
|
||||
} else {
|
||||
nd := net.Dialer{Timeout: mc.cfg.timeout}
|
||||
mc.netConn, err = nd.Dial(mc.cfg.net, mc.cfg.addr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Enable TCP Keepalives on TCP connections
|
||||
if tc, ok := mc.netConn.(*net.TCPConn); ok {
|
||||
if err := tc.SetKeepAlive(true); err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
mc.buf = newBuffer(mc.netConn)
|
||||
|
||||
// Reading Handshake Initialization Packet
|
||||
cipher, err := mc.readInitPacket()
|
||||
if err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Send Client Authentication Packet
|
||||
if err = mc.writeAuthPacket(cipher); err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read Result Packet
|
||||
err = mc.readResultOK()
|
||||
if err != nil {
|
||||
// Retry with old authentication method, if allowed
|
||||
if mc.cfg != nil && mc.cfg.allowOldPasswords && err == ErrOldPassword {
|
||||
if err = mc.writeOldAuthPacket(cipher); err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err = mc.readResultOK(); err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Get max allowed packet size
|
||||
maxap, err := mc.getSystemVar("max_allowed_packet")
|
||||
if err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
mc.maxPacketAllowed = stringToInt(maxap) - 1
|
||||
if mc.maxPacketAllowed < maxPacketSize {
|
||||
mc.maxWriteSize = mc.maxPacketAllowed
|
||||
}
|
||||
|
||||
// Handle DSN Params
|
||||
err = mc.handleParams()
|
||||
if err != nil {
|
||||
mc.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mc, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
sql.Register("mysql", &MySQLDriver{})
|
||||
}
|
1540
Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
Normal file
1540
Godeps/_workspace/src/github.com/go-sql-driver/mysql/driver_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
129
Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go
generated
vendored
Normal file
129
Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Various errors the driver might return. Can change between driver versions.
|
||||
var (
|
||||
ErrInvalidConn = errors.New("Invalid Connection")
|
||||
ErrMalformPkt = errors.New("Malformed Packet")
|
||||
ErrNoTLS = errors.New("TLS encryption requested but server does not support TLS")
|
||||
ErrOldPassword = errors.New("This server only supports the insecure old password authentication. If you still want to use it, please add 'allowOldPasswords=1' to your DSN. See also https://github.com/go-sql-driver/mysql/wiki/old_passwords")
|
||||
ErrOldProtocol = errors.New("MySQL-Server does not support required Protocol 41+")
|
||||
ErrPktSync = errors.New("Commands out of sync. You can't run this command now")
|
||||
ErrPktSyncMul = errors.New("Commands out of sync. Did you run multiple statements at once?")
|
||||
ErrPktTooLarge = errors.New("Packet for query is too large. You can change this value on the server by adjusting the 'max_allowed_packet' variable.")
|
||||
ErrBusyBuffer = errors.New("Busy buffer")
|
||||
)
|
||||
|
||||
var errLog Logger = log.New(os.Stderr, "[MySQL] ", log.Ldate|log.Ltime|log.Lshortfile)
|
||||
|
||||
// Logger is used to log critical error messages.
|
||||
type Logger interface {
|
||||
Print(v ...interface{})
|
||||
}
|
||||
|
||||
// SetLogger is used to set the logger for critical errors.
|
||||
// The initial logger is os.Stderr.
|
||||
func SetLogger(logger Logger) error {
|
||||
if logger == nil {
|
||||
return errors.New("logger is nil")
|
||||
}
|
||||
errLog = logger
|
||||
return nil
|
||||
}
|
||||
|
||||
// MySQLError is an error type which represents a single MySQL error
|
||||
type MySQLError struct {
|
||||
Number uint16
|
||||
Message string
|
||||
}
|
||||
|
||||
func (me *MySQLError) Error() string {
|
||||
return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
|
||||
}
|
||||
|
||||
// MySQLWarnings is an error type which represents a group of one or more MySQL
|
||||
// warnings
|
||||
type MySQLWarnings []MySQLWarning
|
||||
|
||||
func (mws MySQLWarnings) Error() string {
|
||||
var msg string
|
||||
for i, warning := range mws {
|
||||
if i > 0 {
|
||||
msg += "\r\n"
|
||||
}
|
||||
msg += fmt.Sprintf(
|
||||
"%s %s: %s",
|
||||
warning.Level,
|
||||
warning.Code,
|
||||
warning.Message,
|
||||
)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// MySQLWarning is an error type which represents a single MySQL warning.
|
||||
// Warnings are returned in groups only. See MySQLWarnings
|
||||
type MySQLWarning struct {
|
||||
Level string
|
||||
Code string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) getWarnings() (err error) {
|
||||
rows, err := mc.Query("SHOW WARNINGS", nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var warnings = MySQLWarnings{}
|
||||
var values = make([]driver.Value, 3)
|
||||
|
||||
for {
|
||||
err = rows.Next(values)
|
||||
switch err {
|
||||
case nil:
|
||||
warning := MySQLWarning{}
|
||||
|
||||
if raw, ok := values[0].([]byte); ok {
|
||||
warning.Level = string(raw)
|
||||
} else {
|
||||
warning.Level = fmt.Sprintf("%s", values[0])
|
||||
}
|
||||
if raw, ok := values[1].([]byte); ok {
|
||||
warning.Code = string(raw)
|
||||
} else {
|
||||
warning.Code = fmt.Sprintf("%s", values[1])
|
||||
}
|
||||
if raw, ok := values[2].([]byte); ok {
|
||||
warning.Message = string(raw)
|
||||
} else {
|
||||
warning.Message = fmt.Sprintf("%s", values[0])
|
||||
}
|
||||
|
||||
warnings = append(warnings, warning)
|
||||
|
||||
case io.EOF:
|
||||
return warnings
|
||||
|
||||
default:
|
||||
rows.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
42
Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
Normal file
42
Godeps/_workspace/src/github.com/go-sql-driver/mysql/errors_test.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrorsSetLogger(t *testing.T) {
|
||||
previous := errLog
|
||||
defer func() {
|
||||
errLog = previous
|
||||
}()
|
||||
|
||||
// set up logger
|
||||
const expected = "prefix: test\n"
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, 64))
|
||||
logger := log.New(buffer, "prefix: ", 0)
|
||||
|
||||
// print
|
||||
SetLogger(logger)
|
||||
errLog.Print("test")
|
||||
|
||||
// check result
|
||||
if actual := buffer.String(); actual != expected {
|
||||
t.Errorf("expected %q, got %q", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorsStrictIgnoreNotes(t *testing.T) {
|
||||
runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) {
|
||||
dbt.mustExec("DROP TABLE IF EXISTS does_not_exist")
|
||||
})
|
||||
}
|
162
Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go
generated
vendored
Normal file
162
Godeps/_workspace/src/github.com/go-sql-driver/mysql/infile.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
fileRegister map[string]bool
|
||||
readerRegister map[string]func() io.Reader
|
||||
)
|
||||
|
||||
// RegisterLocalFile adds the given file to the file whitelist,
|
||||
// so that it can be used by "LOAD DATA LOCAL INFILE <filepath>".
|
||||
// Alternatively you can allow the use of all local files with
|
||||
// the DSN parameter 'allowAllFiles=true'
|
||||
//
|
||||
// filePath := "/home/gopher/data.csv"
|
||||
// mysql.RegisterLocalFile(filePath)
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE '" + filePath + "' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
//
|
||||
func RegisterLocalFile(filePath string) {
|
||||
// lazy map init
|
||||
if fileRegister == nil {
|
||||
fileRegister = make(map[string]bool)
|
||||
}
|
||||
|
||||
fileRegister[strings.Trim(filePath, `"`)] = true
|
||||
}
|
||||
|
||||
// DeregisterLocalFile removes the given filepath from the whitelist.
|
||||
func DeregisterLocalFile(filePath string) {
|
||||
delete(fileRegister, strings.Trim(filePath, `"`))
|
||||
}
|
||||
|
||||
// RegisterReaderHandler registers a handler function which is used
|
||||
// to receive a io.Reader.
|
||||
// The Reader can be used by "LOAD DATA LOCAL INFILE Reader::<name>".
|
||||
// If the handler returns a io.ReadCloser Close() is called when the
|
||||
// request is finished.
|
||||
//
|
||||
// mysql.RegisterReaderHandler("data", func() io.Reader {
|
||||
// var csvReader io.Reader // Some Reader that returns CSV data
|
||||
// ... // Open Reader here
|
||||
// return csvReader
|
||||
// })
|
||||
// err := db.Exec("LOAD DATA LOCAL INFILE 'Reader::data' INTO TABLE foo")
|
||||
// if err != nil {
|
||||
// ...
|
||||
//
|
||||
func RegisterReaderHandler(name string, handler func() io.Reader) {
|
||||
// lazy map init
|
||||
if readerRegister == nil {
|
||||
readerRegister = make(map[string]func() io.Reader)
|
||||
}
|
||||
|
||||
readerRegister[name] = handler
|
||||
}
|
||||
|
||||
// DeregisterReaderHandler removes the ReaderHandler function with
|
||||
// the given name from the registry.
|
||||
func DeregisterReaderHandler(name string) {
|
||||
delete(readerRegister, name)
|
||||
}
|
||||
|
||||
func deferredClose(err *error, closer io.Closer) {
|
||||
closeErr := closer.Close()
|
||||
if *err == nil {
|
||||
*err = closeErr
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
|
||||
var rdr io.Reader
|
||||
var data []byte
|
||||
|
||||
if strings.HasPrefix(name, "Reader::") { // io.Reader
|
||||
name = name[8:]
|
||||
if handler, inMap := readerRegister[name]; inMap {
|
||||
rdr = handler()
|
||||
if rdr != nil {
|
||||
data = make([]byte, 4+mc.maxWriteSize)
|
||||
|
||||
if cl, ok := rdr.(io.Closer); ok {
|
||||
defer deferredClose(&err, cl)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("Reader '%s' is <nil>", name)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("Reader '%s' is not registered", name)
|
||||
}
|
||||
} else { // File
|
||||
name = strings.Trim(name, `"`)
|
||||
if mc.cfg.allowAllFiles || fileRegister[name] {
|
||||
var file *os.File
|
||||
var fi os.FileInfo
|
||||
|
||||
if file, err = os.Open(name); err == nil {
|
||||
defer deferredClose(&err, file)
|
||||
|
||||
// get file size
|
||||
if fi, err = file.Stat(); err == nil {
|
||||
rdr = file
|
||||
if fileSize := int(fi.Size()); fileSize <= mc.maxWriteSize {
|
||||
data = make([]byte, 4+fileSize)
|
||||
} else if fileSize <= mc.maxPacketAllowed {
|
||||
data = make([]byte, 4+mc.maxWriteSize)
|
||||
} else {
|
||||
err = fmt.Errorf("Local File '%s' too large: Size: %d, Max: %d", name, fileSize, mc.maxPacketAllowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("Local File '%s' is not registered. Use the DSN parameter 'allowAllFiles=true' to allow all files", name)
|
||||
}
|
||||
}
|
||||
|
||||
// send content packets
|
||||
if err == nil {
|
||||
var n int
|
||||
for err == nil {
|
||||
n, err = rdr.Read(data[4:])
|
||||
if n > 0 {
|
||||
if ioErr := mc.writePacket(data[:4+n]); ioErr != nil {
|
||||
return ioErr
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
// send empty packet (termination)
|
||||
if data == nil {
|
||||
data = make([]byte, 4)
|
||||
}
|
||||
if ioErr := mc.writePacket(data[:4]); ioErr != nil {
|
||||
return ioErr
|
||||
}
|
||||
|
||||
// read OK packet
|
||||
if err == nil {
|
||||
return mc.readResultOK()
|
||||
} else {
|
||||
mc.readPacket()
|
||||
}
|
||||
return err
|
||||
}
|
1122
Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go
generated
vendored
Normal file
1122
Godeps/_workspace/src/github.com/go-sql-driver/mysql/packets.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
Godeps/_workspace/src/github.com/go-sql-driver/mysql/result.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/go-sql-driver/mysql/result.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
type mysqlResult struct {
|
||||
affectedRows int64
|
||||
insertId int64
|
||||
}
|
||||
|
||||
func (res *mysqlResult) LastInsertId() (int64, error) {
|
||||
return res.insertId, nil
|
||||
}
|
||||
|
||||
func (res *mysqlResult) RowsAffected() (int64, error) {
|
||||
return res.affectedRows, nil
|
||||
}
|
101
Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go
generated
vendored
Normal file
101
Godeps/_workspace/src/github.com/go-sql-driver/mysql/rows.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"io"
|
||||
)
|
||||
|
||||
type mysqlField struct {
|
||||
name string
|
||||
flags fieldFlag
|
||||
fieldType byte
|
||||
decimals byte
|
||||
}
|
||||
|
||||
type mysqlRows struct {
|
||||
mc *mysqlConn
|
||||
columns []mysqlField
|
||||
}
|
||||
|
||||
type binaryRows struct {
|
||||
mysqlRows
|
||||
}
|
||||
|
||||
type textRows struct {
|
||||
mysqlRows
|
||||
}
|
||||
|
||||
type emptyRows struct{}
|
||||
|
||||
func (rows *mysqlRows) Columns() []string {
|
||||
columns := make([]string, len(rows.columns))
|
||||
for i := range columns {
|
||||
columns[i] = rows.columns[i].name
|
||||
}
|
||||
return columns
|
||||
}
|
||||
|
||||
func (rows *mysqlRows) Close() error {
|
||||
mc := rows.mc
|
||||
if mc == nil {
|
||||
return nil
|
||||
}
|
||||
if mc.netConn == nil {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
|
||||
// Remove unread packets from stream
|
||||
err := mc.readUntilEOF()
|
||||
rows.mc = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (rows *binaryRows) Next(dest []driver.Value) error {
|
||||
if mc := rows.mc; mc != nil {
|
||||
if mc.netConn == nil {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
|
||||
// Fetch next row from stream
|
||||
if err := rows.readRow(dest); err != io.EOF {
|
||||
return err
|
||||
}
|
||||
rows.mc = nil
|
||||
}
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
func (rows *textRows) Next(dest []driver.Value) error {
|
||||
if mc := rows.mc; mc != nil {
|
||||
if mc.netConn == nil {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
|
||||
// Fetch next row from stream
|
||||
if err := rows.readRow(dest); err != io.EOF {
|
||||
return err
|
||||
}
|
||||
rows.mc = nil
|
||||
}
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
func (rows emptyRows) Columns() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rows emptyRows) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rows emptyRows) Next(dest []driver.Value) error {
|
||||
return io.EOF
|
||||
}
|
112
Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go
generated
vendored
Normal file
112
Godeps/_workspace/src/github.com/go-sql-driver/mysql/statement.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
)
|
||||
|
||||
type mysqlStmt struct {
|
||||
mc *mysqlConn
|
||||
id uint32
|
||||
paramCount int
|
||||
columns []mysqlField // cached from the first query
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Close() error {
|
||||
if stmt.mc == nil || stmt.mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
|
||||
err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id)
|
||||
stmt.mc = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) NumInput() int {
|
||||
return stmt.paramCount
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
|
||||
if stmt.mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
// Send command
|
||||
err := stmt.writeExecutePacket(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mc := stmt.mc
|
||||
|
||||
mc.affectedRows = 0
|
||||
mc.insertId = 0
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err == nil {
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
err = mc.readUntilEOF()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Rows
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
if err == nil {
|
||||
return &mysqlResult{
|
||||
affectedRows: int64(mc.affectedRows),
|
||||
insertId: int64(mc.insertId),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
|
||||
if stmt.mc.netConn == nil {
|
||||
errLog.Print(ErrInvalidConn)
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
// Send command
|
||||
err := stmt.writeExecutePacket(args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mc := stmt.mc
|
||||
|
||||
// Read Result
|
||||
resLen, err := mc.readResultSetHeaderPacket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows := new(binaryRows)
|
||||
rows.mc = mc
|
||||
|
||||
if resLen > 0 {
|
||||
// Columns
|
||||
// If not cached, read them and cache them
|
||||
if stmt.columns == nil {
|
||||
rows.columns, err = mc.readColumns(resLen)
|
||||
stmt.columns = rows.columns
|
||||
} else {
|
||||
rows.columns = stmt.columns
|
||||
err = mc.readUntilEOF()
|
||||
}
|
||||
}
|
||||
|
||||
return rows, err
|
||||
}
|
31
Godeps/_workspace/src/github.com/go-sql-driver/mysql/transaction.go
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/go-sql-driver/mysql/transaction.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
type mysqlTx struct {
|
||||
mc *mysqlConn
|
||||
}
|
||||
|
||||
func (tx *mysqlTx) Commit() (err error) {
|
||||
if tx.mc == nil || tx.mc.netConn == nil {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
err = tx.mc.exec("COMMIT")
|
||||
tx.mc = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (tx *mysqlTx) Rollback() (err error) {
|
||||
if tx.mc == nil || tx.mc.netConn == nil {
|
||||
return ErrInvalidConn
|
||||
}
|
||||
err = tx.mc.exec("ROLLBACK")
|
||||
tx.mc = nil
|
||||
return
|
||||
}
|
785
Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go
generated
vendored
Normal file
785
Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils.go
generated
vendored
Normal file
@ -0,0 +1,785 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/tls"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs
|
||||
|
||||
errInvalidDSNUnescaped = errors.New("Invalid DSN: Did you forget to escape a param value?")
|
||||
errInvalidDSNAddr = errors.New("Invalid DSN: Network Address not terminated (missing closing brace)")
|
||||
errInvalidDSNNoSlash = errors.New("Invalid DSN: Missing the slash separating the database name")
|
||||
)
|
||||
|
||||
func init() {
|
||||
tlsConfigRegister = make(map[string]*tls.Config)
|
||||
}
|
||||
|
||||
// RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.
|
||||
// Use the key as a value in the DSN where tls=value.
|
||||
//
|
||||
// rootCertPool := x509.NewCertPool()
|
||||
// pem, err := ioutil.ReadFile("/path/ca-cert.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
|
||||
// log.Fatal("Failed to append PEM.")
|
||||
// }
|
||||
// clientCert := make([]tls.Certificate, 0, 1)
|
||||
// certs, err := tls.LoadX509KeyPair("/path/client-cert.pem", "/path/client-key.pem")
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// clientCert = append(clientCert, certs)
|
||||
// mysql.RegisterTLSConfig("custom", &tls.Config{
|
||||
// RootCAs: rootCertPool,
|
||||
// Certificates: clientCert,
|
||||
// })
|
||||
// db, err := sql.Open("mysql", "user@tcp(localhost:3306)/test?tls=custom")
|
||||
//
|
||||
func RegisterTLSConfig(key string, config *tls.Config) error {
|
||||
if _, isBool := readBool(key); isBool || strings.ToLower(key) == "skip-verify" {
|
||||
return fmt.Errorf("Key '%s' is reserved", key)
|
||||
}
|
||||
|
||||
tlsConfigRegister[key] = config
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeregisterTLSConfig removes the tls.Config associated with key.
|
||||
func DeregisterTLSConfig(key string) {
|
||||
delete(tlsConfigRegister, key)
|
||||
}
|
||||
|
||||
// parseDSN parses the DSN string to a config
|
||||
func parseDSN(dsn string) (cfg *config, err error) {
|
||||
// New config with some default values
|
||||
cfg = &config{
|
||||
loc: time.UTC,
|
||||
collation: defaultCollation,
|
||||
}
|
||||
|
||||
// TODO: use strings.IndexByte when we can depend on Go 1.2
|
||||
|
||||
// [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN]
|
||||
// Find the last '/' (since the password or the net addr might contain a '/')
|
||||
foundSlash := false
|
||||
for i := len(dsn) - 1; i >= 0; i-- {
|
||||
if dsn[i] == '/' {
|
||||
foundSlash = true
|
||||
var j, k int
|
||||
|
||||
// left part is empty if i <= 0
|
||||
if i > 0 {
|
||||
// [username[:password]@][protocol[(address)]]
|
||||
// Find the last '@' in dsn[:i]
|
||||
for j = i; j >= 0; j-- {
|
||||
if dsn[j] == '@' {
|
||||
// username[:password]
|
||||
// Find the first ':' in dsn[:j]
|
||||
for k = 0; k < j; k++ {
|
||||
if dsn[k] == ':' {
|
||||
cfg.passwd = dsn[k+1 : j]
|
||||
break
|
||||
}
|
||||
}
|
||||
cfg.user = dsn[:k]
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// [protocol[(address)]]
|
||||
// Find the first '(' in dsn[j+1:i]
|
||||
for k = j + 1; k < i; k++ {
|
||||
if dsn[k] == '(' {
|
||||
// dsn[i-1] must be == ')' if an address is specified
|
||||
if dsn[i-1] != ')' {
|
||||
if strings.ContainsRune(dsn[k+1:i], ')') {
|
||||
return nil, errInvalidDSNUnescaped
|
||||
}
|
||||
return nil, errInvalidDSNAddr
|
||||
}
|
||||
cfg.addr = dsn[k+1 : i-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
cfg.net = dsn[j+1 : k]
|
||||
}
|
||||
|
||||
// dbname[?param1=value1&...¶mN=valueN]
|
||||
// Find the first '?' in dsn[i+1:]
|
||||
for j = i + 1; j < len(dsn); j++ {
|
||||
if dsn[j] == '?' {
|
||||
if err = parseDSNParams(cfg, dsn[j+1:]); err != nil {
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
cfg.dbname = dsn[i+1 : j]
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundSlash && len(dsn) > 0 {
|
||||
return nil, errInvalidDSNNoSlash
|
||||
}
|
||||
|
||||
// Set default network if empty
|
||||
if cfg.net == "" {
|
||||
cfg.net = "tcp"
|
||||
}
|
||||
|
||||
// Set default address if empty
|
||||
if cfg.addr == "" {
|
||||
switch cfg.net {
|
||||
case "tcp":
|
||||
cfg.addr = "127.0.0.1:3306"
|
||||
case "unix":
|
||||
cfg.addr = "/tmp/mysql.sock"
|
||||
default:
|
||||
return nil, errors.New("Default addr for network '" + cfg.net + "' unknown")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// parseDSNParams parses the DSN "query string"
|
||||
// Values must be url.QueryEscape'ed
|
||||
func parseDSNParams(cfg *config, params string) (err error) {
|
||||
for _, v := range strings.Split(params, "&") {
|
||||
param := strings.SplitN(v, "=", 2)
|
||||
if len(param) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// cfg params
|
||||
switch value := param[1]; param[0] {
|
||||
|
||||
// Disable INFILE whitelist / enable all files
|
||||
case "allowAllFiles":
|
||||
var isBool bool
|
||||
cfg.allowAllFiles, isBool = readBool(value)
|
||||
if !isBool {
|
||||
return fmt.Errorf("Invalid Bool value: %s", value)
|
||||
}
|
||||
|
||||
// Use old authentication mode (pre MySQL 4.1)
|
||||
case "allowOldPasswords":
|
||||
var isBool bool
|
||||
cfg.allowOldPasswords, isBool = readBool(value)
|
||||
if !isBool {
|
||||
return fmt.Errorf("Invalid Bool value: %s", value)
|
||||
}
|
||||
|
||||
// Switch "rowsAffected" mode
|
||||
case "clientFoundRows":
|
||||
var isBool bool
|
||||
cfg.clientFoundRows, isBool = readBool(value)
|
||||
if !isBool {
|
||||
return fmt.Errorf("Invalid Bool value: %s", value)
|
||||
}
|
||||
|
||||
// Collation
|
||||
case "collation":
|
||||
collation, ok := collations[value]
|
||||
if !ok {
|
||||
// Note possibility for false negatives:
|
||||
// could be triggered although the collation is valid if the
|
||||
// collations map does not contain entries the server supports.
|
||||
err = errors.New("unknown collation")
|
||||
return
|
||||
}
|
||||
cfg.collation = collation
|
||||
break
|
||||
|
||||
// Time Location
|
||||
case "loc":
|
||||
if value, err = url.QueryUnescape(value); err != nil {
|
||||
return
|
||||
}
|
||||
cfg.loc, err = time.LoadLocation(value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Dial Timeout
|
||||
case "timeout":
|
||||
cfg.timeout, err = time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TLS-Encryption
|
||||
case "tls":
|
||||
boolValue, isBool := readBool(value)
|
||||
if isBool {
|
||||
if boolValue {
|
||||
cfg.tls = &tls.Config{}
|
||||
}
|
||||
} else {
|
||||
if strings.ToLower(value) == "skip-verify" {
|
||||
cfg.tls = &tls.Config{InsecureSkipVerify: true}
|
||||
} else if tlsConfig, ok := tlsConfigRegister[value]; ok {
|
||||
cfg.tls = tlsConfig
|
||||
} else {
|
||||
return fmt.Errorf("Invalid value / unknown config name: %s", value)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// lazy init
|
||||
if cfg.params == nil {
|
||||
cfg.params = make(map[string]string)
|
||||
}
|
||||
|
||||
if cfg.params[param[0]], err = url.QueryUnescape(value); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the bool value of the input.
|
||||
// The 2nd return value indicates if the input was a valid bool value
|
||||
func readBool(input string) (value bool, valid bool) {
|
||||
switch input {
|
||||
case "1", "true", "TRUE", "True":
|
||||
return true, true
|
||||
case "0", "false", "FALSE", "False":
|
||||
return false, true
|
||||
}
|
||||
|
||||
// Not a valid bool value
|
||||
return
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Authentication *
|
||||
******************************************************************************/
|
||||
|
||||
// Encrypt password using 4.1+ method
|
||||
func scramblePassword(scramble, password []byte) []byte {
|
||||
if len(password) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// stage1Hash = SHA1(password)
|
||||
crypt := sha1.New()
|
||||
crypt.Write(password)
|
||||
stage1 := crypt.Sum(nil)
|
||||
|
||||
// scrambleHash = SHA1(scramble + SHA1(stage1Hash))
|
||||
// inner Hash
|
||||
crypt.Reset()
|
||||
crypt.Write(stage1)
|
||||
hash := crypt.Sum(nil)
|
||||
|
||||
// outer Hash
|
||||
crypt.Reset()
|
||||
crypt.Write(scramble)
|
||||
crypt.Write(hash)
|
||||
scramble = crypt.Sum(nil)
|
||||
|
||||
// token = scrambleHash XOR stage1Hash
|
||||
for i := range scramble {
|
||||
scramble[i] ^= stage1[i]
|
||||
}
|
||||
return scramble
|
||||
}
|
||||
|
||||
// Encrypt password using pre 4.1 (old password) method
|
||||
// https://github.com/atcurtis/mariadb/blob/master/mysys/my_rnd.c
|
||||
type myRnd struct {
|
||||
seed1, seed2 uint32
|
||||
}
|
||||
|
||||
const myRndMaxVal = 0x3FFFFFFF
|
||||
|
||||
// Pseudo random number generator
|
||||
func newMyRnd(seed1, seed2 uint32) *myRnd {
|
||||
return &myRnd{
|
||||
seed1: seed1 % myRndMaxVal,
|
||||
seed2: seed2 % myRndMaxVal,
|
||||
}
|
||||
}
|
||||
|
||||
// Tested to be equivalent to MariaDB's floating point variant
|
||||
// http://play.golang.org/p/QHvhd4qved
|
||||
// http://play.golang.org/p/RG0q4ElWDx
|
||||
func (r *myRnd) NextByte() byte {
|
||||
r.seed1 = (r.seed1*3 + r.seed2) % myRndMaxVal
|
||||
r.seed2 = (r.seed1 + r.seed2 + 33) % myRndMaxVal
|
||||
|
||||
return byte(uint64(r.seed1) * 31 / myRndMaxVal)
|
||||
}
|
||||
|
||||
// Generate binary hash from byte string using insecure pre 4.1 method
|
||||
func pwHash(password []byte) (result [2]uint32) {
|
||||
var add uint32 = 7
|
||||
var tmp uint32
|
||||
|
||||
result[0] = 1345345333
|
||||
result[1] = 0x12345671
|
||||
|
||||
for _, c := range password {
|
||||
// skip spaces and tabs in password
|
||||
if c == ' ' || c == '\t' {
|
||||
continue
|
||||
}
|
||||
|
||||
tmp = uint32(c)
|
||||
result[0] ^= (((result[0] & 63) + add) * tmp) + (result[0] << 8)
|
||||
result[1] += (result[1] << 8) ^ result[0]
|
||||
add += tmp
|
||||
}
|
||||
|
||||
// Remove sign bit (1<<31)-1)
|
||||
result[0] &= 0x7FFFFFFF
|
||||
result[1] &= 0x7FFFFFFF
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Encrypt password using insecure pre 4.1 method
|
||||
func scrambleOldPassword(scramble, password []byte) []byte {
|
||||
if len(password) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
scramble = scramble[:8]
|
||||
|
||||
hashPw := pwHash(password)
|
||||
hashSc := pwHash(scramble)
|
||||
|
||||
r := newMyRnd(hashPw[0]^hashSc[0], hashPw[1]^hashSc[1])
|
||||
|
||||
var out [8]byte
|
||||
for i := range out {
|
||||
out[i] = r.NextByte() + 64
|
||||
}
|
||||
|
||||
mask := r.NextByte()
|
||||
for i := range out {
|
||||
out[i] ^= mask
|
||||
}
|
||||
|
||||
return out[:]
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Time related utils *
|
||||
******************************************************************************/
|
||||
|
||||
// NullTime represents a time.Time that may be NULL.
|
||||
// NullTime implements the Scanner interface so
|
||||
// it can be used as a scan destination:
|
||||
//
|
||||
// var nt NullTime
|
||||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
||||
// ...
|
||||
// if nt.Valid {
|
||||
// // use nt.Time
|
||||
// } else {
|
||||
// // NULL value
|
||||
// }
|
||||
//
|
||||
// This NullTime implementation is not driver-specific
|
||||
type NullTime struct {
|
||||
Time time.Time
|
||||
Valid bool // Valid is true if Time is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
// The value type must be time.Time or string / []byte (formatted time-string),
|
||||
// otherwise Scan fails.
|
||||
func (nt *NullTime) Scan(value interface{}) (err error) {
|
||||
if value == nil {
|
||||
nt.Time, nt.Valid = time.Time{}, false
|
||||
return
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
case time.Time:
|
||||
nt.Time, nt.Valid = v, true
|
||||
return
|
||||
case []byte:
|
||||
nt.Time, err = parseDateTime(string(v), time.UTC)
|
||||
nt.Valid = (err == nil)
|
||||
return
|
||||
case string:
|
||||
nt.Time, err = parseDateTime(v, time.UTC)
|
||||
nt.Valid = (err == nil)
|
||||
return
|
||||
}
|
||||
|
||||
nt.Valid = false
|
||||
return fmt.Errorf("Can't convert %T to time.Time", value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (nt NullTime) Value() (driver.Value, error) {
|
||||
if !nt.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return nt.Time, nil
|
||||
}
|
||||
|
||||
func parseDateTime(str string, loc *time.Location) (t time.Time, err error) {
|
||||
base := "0000-00-00 00:00:00.0000000"
|
||||
switch len(str) {
|
||||
case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
|
||||
if str == base[:len(str)] {
|
||||
return
|
||||
}
|
||||
t, err = time.Parse(timeFormat[:len(str)], str)
|
||||
default:
|
||||
err = fmt.Errorf("Invalid Time-String: %s", str)
|
||||
return
|
||||
}
|
||||
|
||||
// Adjust location
|
||||
if err == nil && loc != time.UTC {
|
||||
y, mo, d := t.Date()
|
||||
h, mi, s := t.Clock()
|
||||
t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Value, error) {
|
||||
switch num {
|
||||
case 0:
|
||||
return time.Time{}, nil
|
||||
case 4:
|
||||
return time.Date(
|
||||
int(binary.LittleEndian.Uint16(data[:2])), // year
|
||||
time.Month(data[2]), // month
|
||||
int(data[3]), // day
|
||||
0, 0, 0, 0,
|
||||
loc,
|
||||
), nil
|
||||
case 7:
|
||||
return time.Date(
|
||||
int(binary.LittleEndian.Uint16(data[:2])), // year
|
||||
time.Month(data[2]), // month
|
||||
int(data[3]), // day
|
||||
int(data[4]), // hour
|
||||
int(data[5]), // minutes
|
||||
int(data[6]), // seconds
|
||||
0,
|
||||
loc,
|
||||
), nil
|
||||
case 11:
|
||||
return time.Date(
|
||||
int(binary.LittleEndian.Uint16(data[:2])), // year
|
||||
time.Month(data[2]), // month
|
||||
int(data[3]), // day
|
||||
int(data[4]), // hour
|
||||
int(data[5]), // minutes
|
||||
int(data[6]), // seconds
|
||||
int(binary.LittleEndian.Uint32(data[7:11]))*1000, // nanoseconds
|
||||
loc,
|
||||
), nil
|
||||
}
|
||||
return nil, fmt.Errorf("Invalid DATETIME-packet length %d", num)
|
||||
}
|
||||
|
||||
// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
|
||||
// if the DATE or DATETIME has the zero value.
|
||||
// It must never be changed.
|
||||
// The current behavior depends on database/sql copying the result.
|
||||
var zeroDateTime = []byte("0000-00-00 00:00:00.000000")
|
||||
|
||||
func formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value, error) {
|
||||
// length expects the deterministic length of the zero value,
|
||||
// negative time and 100+ hours are automatically added if needed
|
||||
const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
|
||||
if len(src) == 0 {
|
||||
if justTime {
|
||||
return zeroDateTime[11 : 11+length], nil
|
||||
}
|
||||
return zeroDateTime[:length], nil
|
||||
}
|
||||
var dst []byte // return value
|
||||
var pt, p1, p2, p3 byte // current digit pair
|
||||
var zOffs byte // offset of value in zeroDateTime
|
||||
if justTime {
|
||||
switch length {
|
||||
case
|
||||
8, // time (can be up to 10 when negative and 100+ hours)
|
||||
10, 11, 12, 13, 14, 15: // time with fractional seconds
|
||||
default:
|
||||
return nil, fmt.Errorf("illegal TIME length %d", length)
|
||||
}
|
||||
switch len(src) {
|
||||
case 8, 12:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid TIME-packet length %d", len(src))
|
||||
}
|
||||
// +2 to enable negative time and 100+ hours
|
||||
dst = make([]byte, 0, length+2)
|
||||
if src[0] == 1 {
|
||||
dst = append(dst, '-')
|
||||
}
|
||||
if src[1] != 0 {
|
||||
hour := uint16(src[1])*24 + uint16(src[5])
|
||||
pt = byte(hour / 100)
|
||||
p1 = byte(hour - 100*uint16(pt))
|
||||
dst = append(dst, digits01[pt])
|
||||
} else {
|
||||
p1 = src[5]
|
||||
}
|
||||
zOffs = 11
|
||||
src = src[6:]
|
||||
} else {
|
||||
switch length {
|
||||
case 10, 19, 21, 22, 23, 24, 25, 26:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
return nil, fmt.Errorf("illegal %s length %d", t, length)
|
||||
}
|
||||
switch len(src) {
|
||||
case 4, 7, 11:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
return nil, fmt.Errorf("illegal %s-packet length %d", t, len(src))
|
||||
}
|
||||
dst = make([]byte, 0, length)
|
||||
// start with the date
|
||||
year := binary.LittleEndian.Uint16(src[:2])
|
||||
pt = byte(year / 100)
|
||||
p1 = byte(year - 100*uint16(pt))
|
||||
p2, p3 = src[2], src[3]
|
||||
dst = append(dst,
|
||||
digits10[pt], digits01[pt],
|
||||
digits10[p1], digits01[p1], '-',
|
||||
digits10[p2], digits01[p2], '-',
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
if length == 10 {
|
||||
return dst, nil
|
||||
}
|
||||
if len(src) == 4 {
|
||||
return append(dst, zeroDateTime[10:length]...), nil
|
||||
}
|
||||
dst = append(dst, ' ')
|
||||
p1 = src[4] // hour
|
||||
src = src[5:]
|
||||
}
|
||||
// p1 is 2-digit hour, src is after hour
|
||||
p2, p3 = src[0], src[1]
|
||||
dst = append(dst,
|
||||
digits10[p1], digits01[p1], ':',
|
||||
digits10[p2], digits01[p2], ':',
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
if length <= byte(len(dst)) {
|
||||
return dst, nil
|
||||
}
|
||||
src = src[2:]
|
||||
if len(src) == 0 {
|
||||
return append(dst, zeroDateTime[19:zOffs+length]...), nil
|
||||
}
|
||||
microsecs := binary.LittleEndian.Uint32(src[:4])
|
||||
p1 = byte(microsecs / 10000)
|
||||
microsecs -= 10000 * uint32(p1)
|
||||
p2 = byte(microsecs / 100)
|
||||
microsecs -= 100 * uint32(p2)
|
||||
p3 = byte(microsecs)
|
||||
switch decimals := zOffs + length - 20; decimals {
|
||||
default:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3], digits01[p3],
|
||||
), nil
|
||||
case 1:
|
||||
return append(dst, '.',
|
||||
digits10[p1],
|
||||
), nil
|
||||
case 2:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
), nil
|
||||
case 3:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2],
|
||||
), nil
|
||||
case 4:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
), nil
|
||||
case 5:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3],
|
||||
), nil
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Convert from and to bytes *
|
||||
******************************************************************************/
|
||||
|
||||
func uint64ToBytes(n uint64) []byte {
|
||||
return []byte{
|
||||
byte(n),
|
||||
byte(n >> 8),
|
||||
byte(n >> 16),
|
||||
byte(n >> 24),
|
||||
byte(n >> 32),
|
||||
byte(n >> 40),
|
||||
byte(n >> 48),
|
||||
byte(n >> 56),
|
||||
}
|
||||
}
|
||||
|
||||
func uint64ToString(n uint64) []byte {
|
||||
var a [20]byte
|
||||
i := 20
|
||||
|
||||
// U+0030 = 0
|
||||
// ...
|
||||
// U+0039 = 9
|
||||
|
||||
var q uint64
|
||||
for n >= 10 {
|
||||
i--
|
||||
q = n / 10
|
||||
a[i] = uint8(n-q*10) + 0x30
|
||||
n = q
|
||||
}
|
||||
|
||||
i--
|
||||
a[i] = uint8(n) + 0x30
|
||||
|
||||
return a[i:]
|
||||
}
|
||||
|
||||
// treats string value as unsigned integer representation
|
||||
func stringToInt(b []byte) int {
|
||||
val := 0
|
||||
for i := range b {
|
||||
val *= 10
|
||||
val += int(b[i] - 0x30)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// returns the string read as a bytes slice, wheter the value is NULL,
|
||||
// the number of bytes read and an error, in case the string is longer than
|
||||
// the input slice
|
||||
func readLengthEncodedString(b []byte) ([]byte, bool, int, error) {
|
||||
// Get length
|
||||
num, isNull, n := readLengthEncodedInteger(b)
|
||||
if num < 1 {
|
||||
return b[n:n], isNull, n, nil
|
||||
}
|
||||
|
||||
n += int(num)
|
||||
|
||||
// Check data length
|
||||
if len(b) >= n {
|
||||
return b[n-int(num) : n], false, n, nil
|
||||
}
|
||||
return nil, false, n, io.EOF
|
||||
}
|
||||
|
||||
// returns the number of bytes skipped and an error, in case the string is
|
||||
// longer than the input slice
|
||||
func skipLengthEncodedString(b []byte) (int, error) {
|
||||
// Get length
|
||||
num, _, n := readLengthEncodedInteger(b)
|
||||
if num < 1 {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
n += int(num)
|
||||
|
||||
// Check data length
|
||||
if len(b) >= n {
|
||||
return n, nil
|
||||
}
|
||||
return n, io.EOF
|
||||
}
|
||||
|
||||
// returns the number read, whether the value is NULL and the number of bytes read
|
||||
func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
|
||||
switch b[0] {
|
||||
|
||||
// 251: NULL
|
||||
case 0xfb:
|
||||
return 0, true, 1
|
||||
|
||||
// 252: value of following 2
|
||||
case 0xfc:
|
||||
return uint64(b[1]) | uint64(b[2])<<8, false, 3
|
||||
|
||||
// 253: value of following 3
|
||||
case 0xfd:
|
||||
return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4
|
||||
|
||||
// 254: value of following 8
|
||||
case 0xfe:
|
||||
return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 |
|
||||
uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 |
|
||||
uint64(b[7])<<48 | uint64(b[8])<<56,
|
||||
false, 9
|
||||
}
|
||||
|
||||
// 0-250: value of first byte
|
||||
return uint64(b[0]), false, 1
|
||||
}
|
||||
|
||||
// encodes a uint64 value and appends it to the given bytes slice
|
||||
func appendLengthEncodedInteger(b []byte, n uint64) []byte {
|
||||
switch {
|
||||
case n <= 250:
|
||||
return append(b, byte(n))
|
||||
|
||||
case n <= 0xffff:
|
||||
return append(b, 0xfc, byte(n), byte(n>>8))
|
||||
|
||||
case n <= 0xffffff:
|
||||
return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16))
|
||||
}
|
||||
return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24),
|
||||
byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56))
|
||||
}
|
212
Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
Normal file
212
Godeps/_workspace/src/github.com/go-sql-driver/mysql/utils_test.go
generated
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
||||
//
|
||||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testDSNs = []struct {
|
||||
in string
|
||||
out string
|
||||
loc *time.Location
|
||||
}{
|
||||
{"username:password@protocol(address)/dbname?param=value", "&{user:username passwd:password net:protocol addr:address dbname:dbname params:map[param:value] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"user@unix(/path/to/socket)/dbname?charset=utf8", "&{user:user passwd: net:unix addr:/path/to/socket dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{user:user passwd:password net:tcp addr:localhost:5555 dbname:dbname params:map[charset:utf8mb4,utf8] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"user:password@/dbname?loc=UTC&timeout=30s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{user:user passwd:password net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:30000000000 collation:224 allowAllFiles:true allowOldPasswords:true clientFoundRows:true}", time.UTC},
|
||||
{"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{user:user passwd:p@ss(word) net:tcp addr:[de:ad:be:ef::ca:fe]:80 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.Local},
|
||||
{"/dbname", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname:dbname params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"@/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"/", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"", "&{user: passwd: net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"user:p@/ssword@/", "&{user:user passwd:p@/ssword net:tcp addr:127.0.0.1:3306 dbname: params:map[] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
{"unix/?arg=%2Fsome%2Fpath.ext", "&{user: passwd: net:unix addr:/tmp/mysql.sock dbname: params:map[arg:/some/path.ext] loc:%p tls:<nil> timeout:0 collation:33 allowAllFiles:false allowOldPasswords:false clientFoundRows:false}", time.UTC},
|
||||
}
|
||||
|
||||
func TestDSNParser(t *testing.T) {
|
||||
var cfg *config
|
||||
var err error
|
||||
var res string
|
||||
|
||||
for i, tst := range testDSNs {
|
||||
cfg, err = parseDSN(tst.in)
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
// pointer not static
|
||||
cfg.tls = nil
|
||||
|
||||
res = fmt.Sprintf("%+v", cfg)
|
||||
if res != fmt.Sprintf(tst.out, tst.loc) {
|
||||
t.Errorf("%d. parseDSN(%q) => %q, want %q", i, tst.in, res, fmt.Sprintf(tst.out, tst.loc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDSNParserInvalid(t *testing.T) {
|
||||
var invalidDSNs = []string{
|
||||
"@net(addr/", // no closing brace
|
||||
"@tcp(/", // no closing brace
|
||||
"tcp(/", // no closing brace
|
||||
"(/", // no closing brace
|
||||
"net(addr)//", // unescaped
|
||||
"user:pass@tcp(1.2.3.4:3306)", // no trailing slash
|
||||
//"/dbname?arg=/some/unescaped/path",
|
||||
}
|
||||
|
||||
for i, tst := range invalidDSNs {
|
||||
if _, err := parseDSN(tst); err == nil {
|
||||
t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkParseDSN(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tst := range testDSNs {
|
||||
if _, err := parseDSN(tst.in); err != nil {
|
||||
b.Error(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestScanNullTime(t *testing.T) {
|
||||
var scanTests = []struct {
|
||||
in interface{}
|
||||
error bool
|
||||
valid bool
|
||||
time time.Time
|
||||
}{
|
||||
{tDate, false, true, tDate},
|
||||
{sDate, false, true, tDate},
|
||||
{[]byte(sDate), false, true, tDate},
|
||||
{tDateTime, false, true, tDateTime},
|
||||
{sDateTime, false, true, tDateTime},
|
||||
{[]byte(sDateTime), false, true, tDateTime},
|
||||
{tDate0, false, true, tDate0},
|
||||
{sDate0, false, true, tDate0},
|
||||
{[]byte(sDate0), false, true, tDate0},
|
||||
{sDateTime0, false, true, tDate0},
|
||||
{[]byte(sDateTime0), false, true, tDate0},
|
||||
{"", true, false, tDate0},
|
||||
{"1234", true, false, tDate0},
|
||||
{0, true, false, tDate0},
|
||||
}
|
||||
|
||||
var nt = NullTime{}
|
||||
var err error
|
||||
|
||||
for _, tst := range scanTests {
|
||||
err = nt.Scan(tst.in)
|
||||
if (err != nil) != tst.error {
|
||||
t.Errorf("%v: expected error status %t, got %t", tst.in, tst.error, (err != nil))
|
||||
}
|
||||
if nt.Valid != tst.valid {
|
||||
t.Errorf("%v: expected valid status %t, got %t", tst.in, tst.valid, nt.Valid)
|
||||
}
|
||||
if nt.Time != tst.time {
|
||||
t.Errorf("%v: expected time %v, got %v", tst.in, tst.time, nt.Time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLengthEncodedInteger(t *testing.T) {
|
||||
var integerTests = []struct {
|
||||
num uint64
|
||||
encoded []byte
|
||||
}{
|
||||
{0x0000000000000000, []byte{0x00}},
|
||||
{0x0000000000000012, []byte{0x12}},
|
||||
{0x00000000000000fa, []byte{0xfa}},
|
||||
{0x0000000000000100, []byte{0xfc, 0x00, 0x01}},
|
||||
{0x0000000000001234, []byte{0xfc, 0x34, 0x12}},
|
||||
{0x000000000000ffff, []byte{0xfc, 0xff, 0xff}},
|
||||
{0x0000000000010000, []byte{0xfd, 0x00, 0x00, 0x01}},
|
||||
{0x0000000000123456, []byte{0xfd, 0x56, 0x34, 0x12}},
|
||||
{0x0000000000ffffff, []byte{0xfd, 0xff, 0xff, 0xff}},
|
||||
{0x0000000001000000, []byte{0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}},
|
||||
{0x123456789abcdef0, []byte{0xfe, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}},
|
||||
{0xffffffffffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
|
||||
}
|
||||
|
||||
for _, tst := range integerTests {
|
||||
num, isNull, numLen := readLengthEncodedInteger(tst.encoded)
|
||||
if isNull {
|
||||
t.Errorf("%x: expected %d, got NULL", tst.encoded, tst.num)
|
||||
}
|
||||
if num != tst.num {
|
||||
t.Errorf("%x: expected %d, got %d", tst.encoded, tst.num, num)
|
||||
}
|
||||
if numLen != len(tst.encoded) {
|
||||
t.Errorf("%x: expected size %d, got %d", tst.encoded, len(tst.encoded), numLen)
|
||||
}
|
||||
encoded := appendLengthEncodedInteger(nil, num)
|
||||
if !bytes.Equal(encoded, tst.encoded) {
|
||||
t.Errorf("%v: expected %x, got %x", num, tst.encoded, encoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOldPass(t *testing.T) {
|
||||
scramble := []byte{9, 8, 7, 6, 5, 4, 3, 2}
|
||||
vectors := []struct {
|
||||
pass string
|
||||
out string
|
||||
}{
|
||||
{" pass", "47575c5a435b4251"},
|
||||
{"pass ", "47575c5a435b4251"},
|
||||
{"123\t456", "575c47505b5b5559"},
|
||||
{"C0mpl!ca ted#PASS123", "5d5d554849584a45"},
|
||||
}
|
||||
for _, tuple := range vectors {
|
||||
ours := scrambleOldPassword(scramble, []byte(tuple.pass))
|
||||
if tuple.out != fmt.Sprintf("%x", ours) {
|
||||
t.Errorf("Failed old password %q", tuple.pass)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatBinaryDateTime(t *testing.T) {
|
||||
rawDate := [11]byte{}
|
||||
binary.LittleEndian.PutUint16(rawDate[:2], 1978) // years
|
||||
rawDate[2] = 12 // months
|
||||
rawDate[3] = 30 // days
|
||||
rawDate[4] = 15 // hours
|
||||
rawDate[5] = 46 // minutes
|
||||
rawDate[6] = 23 // seconds
|
||||
binary.LittleEndian.PutUint32(rawDate[7:], 987654) // microseconds
|
||||
expect := func(expected string, inlen, outlen uint8) {
|
||||
actual, _ := formatBinaryDateTime(rawDate[:inlen], outlen, false)
|
||||
bytes, ok := actual.([]byte)
|
||||
if !ok {
|
||||
t.Errorf("formatBinaryDateTime must return []byte, was %T", actual)
|
||||
}
|
||||
if string(bytes) != expected {
|
||||
t.Errorf(
|
||||
"expected %q, got %q for length in %d, out %d",
|
||||
bytes, actual, inlen, outlen,
|
||||
)
|
||||
}
|
||||
}
|
||||
expect("0000-00-00", 0, 10)
|
||||
expect("0000-00-00 00:00:00", 0, 19)
|
||||
expect("1978-12-30", 4, 10)
|
||||
expect("1978-12-30 15:46:23", 7, 19)
|
||||
expect("1978-12-30 15:46:23.987654", 11, 26)
|
||||
}
|
63
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions.go
generated
vendored
63
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions.go
generated
vendored
@ -1,63 +0,0 @@
|
||||
package convey
|
||||
|
||||
import "github.com/smartystreets/goconvey/convey/assertions"
|
||||
|
||||
var (
|
||||
ShouldEqual = assertions.ShouldEqual
|
||||
ShouldNotEqual = assertions.ShouldNotEqual
|
||||
ShouldAlmostEqual = assertions.ShouldAlmostEqual
|
||||
ShouldNotAlmostEqual = assertions.ShouldNotAlmostEqual
|
||||
ShouldResemble = assertions.ShouldResemble
|
||||
ShouldNotResemble = assertions.ShouldNotResemble
|
||||
ShouldPointTo = assertions.ShouldPointTo
|
||||
ShouldNotPointTo = assertions.ShouldNotPointTo
|
||||
ShouldBeNil = assertions.ShouldBeNil
|
||||
ShouldNotBeNil = assertions.ShouldNotBeNil
|
||||
ShouldBeTrue = assertions.ShouldBeTrue
|
||||
ShouldBeFalse = assertions.ShouldBeFalse
|
||||
ShouldBeZeroValue = assertions.ShouldBeZeroValue
|
||||
|
||||
ShouldBeGreaterThan = assertions.ShouldBeGreaterThan
|
||||
ShouldBeGreaterThanOrEqualTo = assertions.ShouldBeGreaterThanOrEqualTo
|
||||
ShouldBeLessThan = assertions.ShouldBeLessThan
|
||||
ShouldBeLessThanOrEqualTo = assertions.ShouldBeLessThanOrEqualTo
|
||||
ShouldBeBetween = assertions.ShouldBeBetween
|
||||
ShouldNotBeBetween = assertions.ShouldNotBeBetween
|
||||
|
||||
ShouldContain = assertions.ShouldContain
|
||||
ShouldNotContain = assertions.ShouldNotContain
|
||||
ShouldBeIn = assertions.ShouldBeIn
|
||||
ShouldNotBeIn = assertions.ShouldNotBeIn
|
||||
ShouldBeEmpty = assertions.ShouldBeEmpty
|
||||
ShouldNotBeEmpty = assertions.ShouldNotBeEmpty
|
||||
|
||||
ShouldStartWith = assertions.ShouldStartWith
|
||||
ShouldNotStartWith = assertions.ShouldNotStartWith
|
||||
ShouldEndWith = assertions.ShouldEndWith
|
||||
ShouldNotEndWith = assertions.ShouldNotEndWith
|
||||
ShouldBeBlank = assertions.ShouldBeBlank
|
||||
ShouldNotBeBlank = assertions.ShouldNotBeBlank
|
||||
ShouldContainSubstring = assertions.ShouldContainSubstring
|
||||
ShouldNotContainSubstring = assertions.ShouldNotContainSubstring
|
||||
|
||||
ShouldPanic = assertions.ShouldPanic
|
||||
ShouldNotPanic = assertions.ShouldNotPanic
|
||||
ShouldPanicWith = assertions.ShouldPanicWith
|
||||
ShouldNotPanicWith = assertions.ShouldNotPanicWith
|
||||
|
||||
ShouldHaveSameTypeAs = assertions.ShouldHaveSameTypeAs
|
||||
ShouldNotHaveSameTypeAs = assertions.ShouldNotHaveSameTypeAs
|
||||
ShouldImplement = assertions.ShouldImplement
|
||||
ShouldNotImplement = assertions.ShouldNotImplement
|
||||
|
||||
ShouldHappenBefore = assertions.ShouldHappenBefore
|
||||
ShouldHappenOnOrBefore = assertions.ShouldHappenOnOrBefore
|
||||
ShouldHappenAfter = assertions.ShouldHappenAfter
|
||||
ShouldHappenOnOrAfter = assertions.ShouldHappenOnOrAfter
|
||||
ShouldHappenBetween = assertions.ShouldHappenBetween
|
||||
ShouldHappenOnOrBetween = assertions.ShouldHappenOnOrBetween
|
||||
ShouldNotHappenOnOrBetween = assertions.ShouldNotHappenOnOrBetween
|
||||
ShouldHappenWithin = assertions.ShouldHappenWithin
|
||||
ShouldNotHappenWithin = assertions.ShouldNotHappenWithin
|
||||
ShouldBeChronological = assertions.ShouldBeChronological
|
||||
)
|
140
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/collections.go
generated
vendored
140
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/collections.go
generated
vendored
@ -1,140 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/jacobsa/oglematchers"
|
||||
)
|
||||
|
||||
// ShouldContain receives exactly two parameters. The first is a slice and the
|
||||
// second is a proposed member. Membership is determined using ShouldEqual.
|
||||
func ShouldContain(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
|
||||
typeName := reflect.TypeOf(actual)
|
||||
|
||||
if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
|
||||
}
|
||||
return fmt.Sprintf(shouldHaveContained, typeName, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotContain receives exactly two parameters. The first is a slice and the
|
||||
// second is a proposed member. Membership is determinied using ShouldEqual.
|
||||
func ShouldNotContain(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
typeName := reflect.TypeOf(actual)
|
||||
|
||||
if matchError := oglematchers.Contains(expected[0]).Matches(actual); matchError != nil {
|
||||
if fmt.Sprintf("%v", matchError) == "which is not a slice or array" {
|
||||
return fmt.Sprintf(shouldHaveBeenAValidCollection, typeName)
|
||||
}
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveContained, typeName, expected[0])
|
||||
}
|
||||
|
||||
// ShouldBeIn receives at least 2 parameters. The first is a proposed member of the collection
|
||||
// that is passed in either as the second parameter, or of the collection that is comprised
|
||||
// of all the remaining parameters. This assertion ensures that the proposed member is in
|
||||
// the collection (using ShouldEqual).
|
||||
func ShouldBeIn(actual interface{}, expected ...interface{}) string {
|
||||
if fail := atLeast(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if len(expected) == 1 {
|
||||
return shouldBeIn(actual, expected[0])
|
||||
}
|
||||
return shouldBeIn(actual, expected)
|
||||
}
|
||||
func shouldBeIn(actual interface{}, expected interface{}) string {
|
||||
if matchError := oglematchers.Contains(actual).Matches(expected); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenIn, actual, reflect.TypeOf(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeIn receives at least 2 parameters. The first is a proposed member of the collection
|
||||
// that is passed in either as the second parameter, or of the collection that is comprised
|
||||
// of all the remaining parameters. This assertion ensures that the proposed member is NOT in
|
||||
// the collection (using ShouldEqual).
|
||||
func ShouldNotBeIn(actual interface{}, expected ...interface{}) string {
|
||||
if fail := atLeast(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if len(expected) == 1 {
|
||||
return shouldNotBeIn(actual, expected[0])
|
||||
}
|
||||
return shouldNotBeIn(actual, expected)
|
||||
}
|
||||
func shouldNotBeIn(actual interface{}, expected interface{}) string {
|
||||
if matchError := oglematchers.Contains(actual).Matches(expected); matchError == nil {
|
||||
return fmt.Sprintf(shouldNotHaveBeenIn, actual, reflect.TypeOf(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeEmpty receives a single parameter (actual) and determines whether or not
|
||||
// calling len(actual) would return `0`. It obeys the rules specified by the len
|
||||
// function for determining length: http://golang.org/pkg/builtin/#len
|
||||
func ShouldBeEmpty(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if actual == nil {
|
||||
return success
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(actual)
|
||||
switch value.Kind() {
|
||||
case reflect.Slice:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Chan:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Map:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.String:
|
||||
if value.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
case reflect.Ptr:
|
||||
elem := value.Elem()
|
||||
kind := elem.Kind()
|
||||
if (kind == reflect.Slice || kind == reflect.Array) && elem.Len() == 0 {
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(shouldHaveBeenEmpty, actual)
|
||||
}
|
||||
|
||||
// ShouldNotBeEmpty receives a single parameter (actual) and determines whether or not
|
||||
// calling len(actual) would return a value greater than zero. It obeys the rules
|
||||
// specified by the `len` function for determining length: http://golang.org/pkg/builtin/#len
|
||||
func ShouldNotBeEmpty(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if empty := ShouldBeEmpty(actual, expected...); empty != success {
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveBeenEmpty, actual)
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestShouldContain(t *testing.T) {
|
||||
fail(t, so([]int{}, ShouldContain), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so([]int{}, ShouldContain, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(Thing1{}, ShouldContain, 1), "You must provide a valid container (was assertions.Thing1)!")
|
||||
fail(t, so(nil, ShouldContain, 1), "You must provide a valid container (was <nil>)!")
|
||||
fail(t, so([]int{1}, ShouldContain, 2), "Expected the container ([]int) to contain: '2' (but it didn't)!")
|
||||
|
||||
pass(t, so([]int{1}, ShouldContain, 1))
|
||||
pass(t, so([]int{1, 2, 3}, ShouldContain, 2))
|
||||
}
|
||||
|
||||
func TestShouldNotContain(t *testing.T) {
|
||||
fail(t, so([]int{}, ShouldNotContain), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so([]int{}, ShouldNotContain, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(Thing1{}, ShouldNotContain, 1), "You must provide a valid container (was assertions.Thing1)!")
|
||||
fail(t, so(nil, ShouldNotContain, 1), "You must provide a valid container (was <nil>)!")
|
||||
|
||||
fail(t, so([]int{1}, ShouldNotContain, 1), "Expected the container ([]int) NOT to contain: '1' (but it did)!")
|
||||
fail(t, so([]int{1, 2, 3}, ShouldNotContain, 2), "Expected the container ([]int) NOT to contain: '2' (but it did)!")
|
||||
|
||||
pass(t, so([]int{1}, ShouldNotContain, 2))
|
||||
}
|
||||
|
||||
func TestShouldBeIn(t *testing.T) {
|
||||
fail(t, so(4, ShouldBeIn), shouldHaveProvidedCollectionMembers)
|
||||
|
||||
container := []int{1, 2, 3, 4}
|
||||
pass(t, so(4, ShouldBeIn, container))
|
||||
pass(t, so(4, ShouldBeIn, 1, 2, 3, 4))
|
||||
|
||||
fail(t, so(4, ShouldBeIn, 1, 2, 3), "Expected '4' to be in the container ([]interface {}, but it wasn't)!")
|
||||
fail(t, so(4, ShouldBeIn, []int{1, 2, 3}), "Expected '4' to be in the container ([]int, but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldNotBeIn(t *testing.T) {
|
||||
fail(t, so(4, ShouldNotBeIn), shouldHaveProvidedCollectionMembers)
|
||||
|
||||
container := []int{1, 2, 3, 4}
|
||||
pass(t, so(42, ShouldNotBeIn, container))
|
||||
pass(t, so(42, ShouldNotBeIn, 1, 2, 3, 4))
|
||||
|
||||
fail(t, so(2, ShouldNotBeIn, 1, 2, 3), "Expected '2' NOT to be in the container ([]interface {}, but it was)!")
|
||||
fail(t, so(2, ShouldNotBeIn, []int{1, 2, 3}), "Expected '2' NOT to be in the container ([]int, but it was)!")
|
||||
}
|
||||
|
||||
func TestShouldBeEmpty(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeEmpty, 2, 3), "This assertion requires exactly 0 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so([]int{}, ShouldBeEmpty)) // empty slice
|
||||
pass(t, so([]interface{}{}, ShouldBeEmpty)) // empty slice
|
||||
pass(t, so(map[string]int{}, ShouldBeEmpty)) // empty map
|
||||
pass(t, so("", ShouldBeEmpty)) // empty string
|
||||
pass(t, so(&[]int{}, ShouldBeEmpty)) // pointer to empty slice
|
||||
pass(t, so(&[0]int{}, ShouldBeEmpty)) // pointer to empty array
|
||||
pass(t, so(nil, ShouldBeEmpty)) // nil
|
||||
pass(t, so(make(chan string), ShouldBeEmpty)) // empty channel
|
||||
|
||||
fail(t, so([]int{1}, ShouldBeEmpty), "Expected [1] to be empty (but it wasn't)!") // non-empty slice
|
||||
fail(t, so([]interface{}{1}, ShouldBeEmpty), "Expected [1] to be empty (but it wasn't)!") // non-empty slice
|
||||
fail(t, so(map[string]int{"hi": 0}, ShouldBeEmpty), "Expected map[hi:0] to be empty (but it wasn't)!") // non-empty map
|
||||
fail(t, so("hi", ShouldBeEmpty), "Expected hi to be empty (but it wasn't)!") // non-empty string
|
||||
fail(t, so(&[]int{1}, ShouldBeEmpty), "Expected &[1] to be empty (but it wasn't)!") // pointer to non-empty slice
|
||||
fail(t, so(&[1]int{1}, ShouldBeEmpty), "Expected &[1] to be empty (but it wasn't)!") // pointer to non-empty array
|
||||
c := make(chan int, 1) // non-empty channel
|
||||
go func() { c <- 1 }()
|
||||
time.Sleep(time.Millisecond)
|
||||
fail(t, so(c, ShouldBeEmpty), fmt.Sprintf("Expected %+v to be empty (but it wasn't)!", c))
|
||||
}
|
||||
|
||||
func TestShouldNotBeEmpty(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotBeEmpty, 2, 3), "This assertion requires exactly 0 comparison values (you provided 2).")
|
||||
|
||||
fail(t, so([]int{}, ShouldNotBeEmpty), "Expected [] to NOT be empty (but it was)!") // empty slice
|
||||
fail(t, so([]interface{}{}, ShouldNotBeEmpty), "Expected [] to NOT be empty (but it was)!") // empty slice
|
||||
fail(t, so(map[string]int{}, ShouldNotBeEmpty), "Expected map[] to NOT be empty (but it was)!") // empty map
|
||||
fail(t, so("", ShouldNotBeEmpty), "Expected to NOT be empty (but it was)!") // empty string
|
||||
fail(t, so(&[]int{}, ShouldNotBeEmpty), "Expected &[] to NOT be empty (but it was)!") // pointer to empty slice
|
||||
fail(t, so(&[0]int{}, ShouldNotBeEmpty), "Expected &[] to NOT be empty (but it was)!") // pointer to empty array
|
||||
fail(t, so(nil, ShouldNotBeEmpty), "Expected <nil> to NOT be empty (but it was)!") // nil
|
||||
c := make(chan int, 0) // non-empty channel
|
||||
fail(t, so(c, ShouldNotBeEmpty), fmt.Sprintf("Expected %+v to NOT be empty (but it was)!", c)) // empty channel
|
||||
|
||||
pass(t, so([]int{1}, ShouldNotBeEmpty)) // non-empty slice
|
||||
pass(t, so([]interface{}{1}, ShouldNotBeEmpty)) // non-empty slice
|
||||
pass(t, so(map[string]int{"hi": 0}, ShouldNotBeEmpty)) // non-empty map
|
||||
pass(t, so("hi", ShouldNotBeEmpty)) // non-empty string
|
||||
pass(t, so(&[]int{1}, ShouldNotBeEmpty)) // pointer to non-empty slice
|
||||
pass(t, so(&[1]int{1}, ShouldNotBeEmpty)) // pointer to non-empty array
|
||||
c = make(chan int, 1)
|
||||
go func() { c <- 1 }()
|
||||
time.Sleep(time.Millisecond)
|
||||
pass(t, so(c, ShouldNotBeEmpty))
|
||||
}
|
3
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/doc.go
generated
vendored
3
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/doc.go
generated
vendored
@ -1,3 +0,0 @@
|
||||
// Package assertions contains the implementations for all assertions which
|
||||
// are referenced in the convey package for use with the So(...) method.
|
||||
package assertions
|
281
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality.go
generated
vendored
281
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality.go
generated
vendored
@ -1,281 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/jacobsa/oglematchers"
|
||||
)
|
||||
|
||||
// default acceptable delta for ShouldAlmostEqual
|
||||
const defaultDelta = 0.0000000001
|
||||
|
||||
// ShouldEqual receives exactly two parameters and does an equality check.
|
||||
func ShouldEqual(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
return shouldEqual(actual, expected[0])
|
||||
}
|
||||
func shouldEqual(actual, expected interface{}) (message string) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual))
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
if matchError := oglematchers.Equals(expected).Matches(actual); matchError != nil {
|
||||
message = serializer.serialize(expected, actual, fmt.Sprintf(shouldHaveBeenEqual, expected, actual))
|
||||
return
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotEqual receives exactly two parameters and does an inequality check.
|
||||
func ShouldNotEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if ShouldEqual(actual, expected[0]) == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenEqual, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldAlmostEqual makes sure that two parameters are close enough to being equal.
|
||||
// The acceptable delta may be specified with a third argument,
|
||||
// or a very small default delta will be used.
|
||||
func ShouldAlmostEqual(actual interface{}, expected ...interface{}) string {
|
||||
actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
|
||||
|
||||
if err != "" {
|
||||
return err
|
||||
}
|
||||
|
||||
if math.Abs(actualFloat-expectedFloat) <= deltaFloat {
|
||||
return success
|
||||
} else {
|
||||
return fmt.Sprintf(shouldHaveBeenAlmostEqual, actualFloat, expectedFloat)
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldNotAlmostEqual is the inverse of ShouldAlmostEqual
|
||||
func ShouldNotAlmostEqual(actual interface{}, expected ...interface{}) string {
|
||||
actualFloat, expectedFloat, deltaFloat, err := cleanAlmostEqualInput(actual, expected...)
|
||||
|
||||
if err != "" {
|
||||
return err
|
||||
}
|
||||
|
||||
if math.Abs(actualFloat-expectedFloat) > deltaFloat {
|
||||
return success
|
||||
} else {
|
||||
return fmt.Sprintf(shouldHaveNotBeenAlmostEqual, actualFloat, expectedFloat)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanAlmostEqualInput(actual interface{}, expected ...interface{}) (float64, float64, float64, string) {
|
||||
deltaFloat := 0.0000000001
|
||||
|
||||
if len(expected) == 0 {
|
||||
return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided neither)"
|
||||
} else if len(expected) == 2 {
|
||||
delta, err := getFloat(expected[1])
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, "delta must be a numerical type"
|
||||
}
|
||||
|
||||
deltaFloat = delta
|
||||
} else if len(expected) > 2 {
|
||||
return 0.0, 0.0, 0.0, "This assertion requires exactly one comparison value and an optional delta (you provided more values)"
|
||||
}
|
||||
|
||||
actualFloat, err := getFloat(actual)
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, err.Error()
|
||||
}
|
||||
|
||||
expectedFloat, err := getFloat(expected[0])
|
||||
|
||||
if err != nil {
|
||||
return 0.0, 0.0, 0.0, err.Error()
|
||||
}
|
||||
|
||||
return actualFloat, expectedFloat, deltaFloat, ""
|
||||
}
|
||||
|
||||
// returns the float value of any real number, or error if it is not a numerical type
|
||||
func getFloat(num interface{}) (float64, error) {
|
||||
numValue := reflect.ValueOf(num)
|
||||
numKind := numValue.Kind()
|
||||
|
||||
if numKind == reflect.Int ||
|
||||
numKind == reflect.Int8 ||
|
||||
numKind == reflect.Int16 ||
|
||||
numKind == reflect.Int32 ||
|
||||
numKind == reflect.Int64 {
|
||||
return float64(numValue.Int()), nil
|
||||
} else if numKind == reflect.Uint ||
|
||||
numKind == reflect.Uint8 ||
|
||||
numKind == reflect.Uint16 ||
|
||||
numKind == reflect.Uint32 ||
|
||||
numKind == reflect.Uint64 {
|
||||
return float64(numValue.Uint()), nil
|
||||
} else if numKind == reflect.Float32 ||
|
||||
numKind == reflect.Float64 {
|
||||
return numValue.Float(), nil
|
||||
} else {
|
||||
return 0.0, errors.New("must be a numerical type, but was " + numKind.String())
|
||||
}
|
||||
}
|
||||
|
||||
// ShouldResemble receives exactly two parameters and does a deep equal check (see reflect.DeepEqual)
|
||||
func ShouldResemble(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
|
||||
if matchError := oglematchers.DeepEquals(expected[0]).Matches(actual); matchError != nil {
|
||||
message := fmt.Sprintf(
|
||||
shouldHaveResembled,
|
||||
expected[0], expected[0],
|
||||
actual, actual,
|
||||
)
|
||||
return serializer.serialize(
|
||||
expected[0], actual, message)
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotResemble receives exactly two parameters and does an inverse deep equal check (see reflect.DeepEqual)
|
||||
func ShouldNotResemble(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
} else if ShouldResemble(actual, expected[0]) == success {
|
||||
return fmt.Sprintf(
|
||||
shouldNotHaveResembled,
|
||||
actual, actual,
|
||||
expected[0], expected[0],
|
||||
)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldPointTo receives exactly two parameters and checks to see that they point to the same address.
|
||||
func ShouldPointTo(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
return shouldPointTo(actual, expected[0])
|
||||
|
||||
}
|
||||
func shouldPointTo(actual, expected interface{}) string {
|
||||
actualValue := reflect.ValueOf(actual)
|
||||
expectedValue := reflect.ValueOf(expected)
|
||||
|
||||
if ShouldNotBeNil(actual) != success {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "nil")
|
||||
} else if ShouldNotBeNil(expected) != success {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "nil")
|
||||
} else if actualValue.Kind() != reflect.Ptr {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "first", "not")
|
||||
} else if expectedValue.Kind() != reflect.Ptr {
|
||||
return fmt.Sprintf(shouldHaveBeenNonNilPointer, "second", "not")
|
||||
} else if ShouldEqual(actualValue.Pointer(), expectedValue.Pointer()) != success {
|
||||
actualAddress := reflect.ValueOf(actual).Pointer()
|
||||
expectedAddress := reflect.ValueOf(expected).Pointer()
|
||||
return serializer.serialize(expectedAddress, actualAddress, fmt.Sprintf(shouldHavePointedTo,
|
||||
actual, actualAddress,
|
||||
expected, expectedAddress))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotPointTo receives exactly two parameters and checks to see that they point to different addresess.
|
||||
func ShouldNotPointTo(actual interface{}, expected ...interface{}) string {
|
||||
if message := need(1, expected); message != success {
|
||||
return message
|
||||
}
|
||||
compare := ShouldPointTo(actual, expected[0])
|
||||
if strings.HasPrefix(compare, shouldBePointers) {
|
||||
return compare
|
||||
} else if compare == success {
|
||||
return fmt.Sprintf(shouldNotHavePointedTo, actual, expected[0], reflect.ValueOf(actual).Pointer())
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeNil receives a single parameter and ensures that it is nil.
|
||||
func ShouldBeNil(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual == nil {
|
||||
return success
|
||||
} else if interfaceHasNilValue(actual) {
|
||||
return success
|
||||
}
|
||||
return fmt.Sprintf(shouldHaveBeenNil, actual)
|
||||
}
|
||||
func interfaceHasNilValue(actual interface{}) bool {
|
||||
value := reflect.ValueOf(actual)
|
||||
kind := value.Kind()
|
||||
nilable := kind == reflect.Slice ||
|
||||
kind == reflect.Chan ||
|
||||
kind == reflect.Func ||
|
||||
kind == reflect.Ptr ||
|
||||
kind == reflect.Map
|
||||
|
||||
// Careful: reflect.Value.IsNil() will panic unless it's an interface, chan, map, func, slice, or ptr
|
||||
// Reference: http://golang.org/pkg/reflect/#Value.IsNil
|
||||
return nilable && value.IsNil()
|
||||
}
|
||||
|
||||
// ShouldNotBeNil receives a single parameter and ensures that it is not nil.
|
||||
func ShouldNotBeNil(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if ShouldBeNil(actual) == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenNil, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeTrue receives a single parameter and ensures that it is true.
|
||||
func ShouldBeTrue(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual != true {
|
||||
return fmt.Sprintf(shouldHaveBeenTrue, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeFalse receives a single parameter and ensures that it is false.
|
||||
func ShouldBeFalse(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
} else if actual != false {
|
||||
return fmt.Sprintf(shouldHaveBeenFalse, actual)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeZeroValue receives a single parameter and ensures that it is
|
||||
// the Go equivalent of the default value, or "zero" value.
|
||||
func ShouldBeZeroValue(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
zeroVal := reflect.Zero(reflect.TypeOf(actual)).Interface()
|
||||
if !reflect.DeepEqual(zeroVal, actual) {
|
||||
return serializer.serialize(zeroVal, actual, fmt.Sprintf(shouldHaveBeenZeroValue, actual))
|
||||
}
|
||||
return success
|
||||
}
|
256
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality_test.go
generated
vendored
256
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/equality_test.go
generated
vendored
@ -1,256 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShouldEqual(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so(1, ShouldEqual), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldEqual, 1, 2), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
fail(t, so(1, ShouldEqual, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
pass(t, so(1, ShouldEqual, 1))
|
||||
fail(t, so(1, ShouldEqual, 2), "2|1|Expected: '2' Actual: '1' (Should be equal)")
|
||||
|
||||
pass(t, so(true, ShouldEqual, true))
|
||||
fail(t, so(true, ShouldEqual, false), "false|true|Expected: 'false' Actual: 'true' (Should be equal)")
|
||||
|
||||
pass(t, so("hi", ShouldEqual, "hi"))
|
||||
fail(t, so("hi", ShouldEqual, "bye"), "bye|hi|Expected: 'bye' Actual: 'hi' (Should be equal)")
|
||||
|
||||
pass(t, so(42, ShouldEqual, uint(42)))
|
||||
|
||||
fail(t, so(Thing1{"hi"}, ShouldEqual, Thing1{}), "{}|{hi}|Expected: '{}' Actual: '{hi}' (Should be equal)")
|
||||
fail(t, so(Thing1{"hi"}, ShouldEqual, Thing1{"hi"}), "{hi}|{hi}|Expected: '{hi}' Actual: '{hi}' (Should be equal)")
|
||||
fail(t, so(&Thing1{"hi"}, ShouldEqual, &Thing1{"hi"}), "&{hi}|&{hi}|Expected: '&{hi}' Actual: '&{hi}' (Should be equal)")
|
||||
|
||||
fail(t, so(Thing1{}, ShouldEqual, Thing2{}), "{}|{}|Expected: '{}' Actual: '{}' (Should be equal)")
|
||||
}
|
||||
|
||||
func TestShouldNotEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotEqual), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldNotEqual, 1, 2), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
fail(t, so(1, ShouldNotEqual, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
pass(t, so(1, ShouldNotEqual, 2))
|
||||
fail(t, so(1, ShouldNotEqual, 1), "Expected '1' to NOT equal '1' (but it did)!")
|
||||
|
||||
pass(t, so(true, ShouldNotEqual, false))
|
||||
fail(t, so(true, ShouldNotEqual, true), "Expected 'true' to NOT equal 'true' (but it did)!")
|
||||
|
||||
pass(t, so("hi", ShouldNotEqual, "bye"))
|
||||
fail(t, so("hi", ShouldNotEqual, "hi"), "Expected 'hi' to NOT equal 'hi' (but it did)!")
|
||||
|
||||
pass(t, so(&Thing1{"hi"}, ShouldNotEqual, &Thing1{"hi"}))
|
||||
pass(t, so(Thing1{"hi"}, ShouldNotEqual, Thing1{"hi"}))
|
||||
pass(t, so(Thing1{}, ShouldNotEqual, Thing1{}))
|
||||
pass(t, so(Thing1{}, ShouldNotEqual, Thing2{}))
|
||||
}
|
||||
|
||||
func TestShouldAlmostEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldAlmostEqual), "This assertion requires exactly one comparison value and an optional delta (you provided neither)")
|
||||
fail(t, so(1, ShouldAlmostEqual, 1, 2, 3), "This assertion requires exactly one comparison value and an optional delta (you provided more values)")
|
||||
|
||||
// with the default delta
|
||||
pass(t, so(1, ShouldAlmostEqual, .99999999999999))
|
||||
pass(t, so(1.3612499999999996, ShouldAlmostEqual, 1.36125))
|
||||
pass(t, so(0.7285312499999999, ShouldAlmostEqual, 0.72853125))
|
||||
fail(t, so(1, ShouldAlmostEqual, .99), "Expected '1' to almost equal '0.99' (but it didn't)!")
|
||||
|
||||
// with a different delta
|
||||
pass(t, so(100.0, ShouldAlmostEqual, 110.0, 10.0))
|
||||
fail(t, so(100.0, ShouldAlmostEqual, 111.0, 10.5), "Expected '100' to almost equal '111' (but it didn't)!")
|
||||
|
||||
// ints should work
|
||||
pass(t, so(100, ShouldAlmostEqual, 100.0))
|
||||
fail(t, so(100, ShouldAlmostEqual, 99.0), "Expected '100' to almost equal '99' (but it didn't)!")
|
||||
|
||||
// float32 should work
|
||||
pass(t, so(float64(100.0), ShouldAlmostEqual, float32(100.0)))
|
||||
fail(t, so(float32(100.0), ShouldAlmostEqual, 99.0, float32(0.1)), "Expected '100' to almost equal '99' (but it didn't)!")
|
||||
}
|
||||
|
||||
func TestShouldNotAlmostEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotAlmostEqual), "This assertion requires exactly one comparison value and an optional delta (you provided neither)")
|
||||
fail(t, so(1, ShouldNotAlmostEqual, 1, 2, 3), "This assertion requires exactly one comparison value and an optional delta (you provided more values)")
|
||||
|
||||
// with the default delta
|
||||
fail(t, so(1, ShouldNotAlmostEqual, .99999999999999), "Expected '1' to NOT almost equal '0.99999999999999' (but it did)!")
|
||||
fail(t, so(1.3612499999999996, ShouldNotAlmostEqual, 1.36125), "Expected '1.3612499999999996' to NOT almost equal '1.36125' (but it did)!")
|
||||
pass(t, so(1, ShouldNotAlmostEqual, .99))
|
||||
|
||||
// with a different delta
|
||||
fail(t, so(100.0, ShouldNotAlmostEqual, 110.0, 10.0), "Expected '100' to NOT almost equal '110' (but it did)!")
|
||||
pass(t, so(100.0, ShouldNotAlmostEqual, 111.0, 10.5))
|
||||
|
||||
// ints should work
|
||||
fail(t, so(100, ShouldNotAlmostEqual, 100.0), "Expected '100' to NOT almost equal '100' (but it did)!")
|
||||
pass(t, so(100, ShouldNotAlmostEqual, 99.0))
|
||||
|
||||
// float32 should work
|
||||
fail(t, so(float64(100.0), ShouldNotAlmostEqual, float32(100.0)), "Expected '100' to NOT almost equal '100' (but it did)!")
|
||||
pass(t, so(float32(100.0), ShouldNotAlmostEqual, 99.0, float32(0.1)))
|
||||
}
|
||||
|
||||
func TestShouldResemble(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so(Thing1{"hi"}, ShouldResemble), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"hi"}, Thing1{"hi"}), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"hi"}))
|
||||
fail(t, so(Thing1{"hi"}, ShouldResemble, Thing1{"bye"}), "{bye}|{hi}|Expected: 'assertions.Thing1({a:bye})' Actual: 'assertions.Thing1({a:hi})' (Should resemble)!")
|
||||
}
|
||||
|
||||
func TestShouldNotResemble(t *testing.T) {
|
||||
fail(t, so(Thing1{"hi"}, ShouldNotResemble), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"hi"}, Thing1{"hi"}), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"bye"}))
|
||||
fail(t, so(Thing1{"hi"}, ShouldNotResemble, Thing1{"hi"}),
|
||||
"Expected 'assertions.Thing1({a:hi})' to NOT resemble 'assertions.Thing1({a:hi})' (but it did)!")
|
||||
|
||||
pass(t, so(map[string]string{"hi": "bye"}, ShouldResemble, map[string]string{"hi": "bye"}))
|
||||
fail(t, so(StringStringMapAlias{"hi": "bye"}, ShouldResemble, map[string]string{"hi": "bye"}),
|
||||
"map[hi:bye]|map[hi:bye]|Expected: 'map[string]string(map[hi:bye])' Actual: 'assertions.StringStringMapAlias(map[hi:bye])' (Should resemble)!")
|
||||
pass(t, so(IntAlias(42), ShouldNotResemble, 42))
|
||||
fail(t, so(IntAlias(42), ShouldResemble, 42), "42|42|Expected: 'int(42)' Actual: 'assertions.IntAlias(42)' (Should resemble)!")
|
||||
fail(t, so(StringAlias("hi"), ShouldResemble, "hi"), "hi|hi|Expected: 'string(hi)' Actual: 'assertions.StringAlias(hi)' (Should resemble)!")
|
||||
|
||||
pass(t, so(StringSliceAlias{"hi", "bye"}, ShouldNotResemble, []string{"hi", "bye"}))
|
||||
fail(t, so(StringSliceAlias{"hi", "bye"}, ShouldResemble, []string{"hi", "bye"}),
|
||||
"[hi bye]|[hi bye]|Expected: '[]string([hi bye])' Actual: 'assertions.StringSliceAlias([hi bye])' (Should resemble)!")
|
||||
}
|
||||
|
||||
func TestShouldPointTo(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
t1 := &Thing1{}
|
||||
t2 := t1
|
||||
t3 := &Thing1{}
|
||||
|
||||
pointer1 := reflect.ValueOf(t1).Pointer()
|
||||
pointer3 := reflect.ValueOf(t3).Pointer()
|
||||
|
||||
fail(t, so(t1, ShouldPointTo), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(t1, ShouldPointTo, t2, t3), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(t1, ShouldPointTo, t2))
|
||||
fail(t, so(t1, ShouldPointTo, t3), fmt.Sprintf(
|
||||
"%v|%v|Expected '&{a:}' (address: '%v') and '&{a:}' (address: '%v') to be the same address (but their weren't)!",
|
||||
pointer3, pointer1, pointer1, pointer3))
|
||||
|
||||
t4 := Thing1{}
|
||||
t5 := t4
|
||||
|
||||
fail(t, so(t4, ShouldPointTo, t5), "Both arguments should be pointers (the first was not)!")
|
||||
fail(t, so(&t4, ShouldPointTo, t5), "Both arguments should be pointers (the second was not)!")
|
||||
fail(t, so(nil, ShouldPointTo, nil), "Both arguments should be pointers (the first was nil)!")
|
||||
fail(t, so(&t4, ShouldPointTo, nil), "Both arguments should be pointers (the second was nil)!")
|
||||
}
|
||||
|
||||
func TestShouldNotPointTo(t *testing.T) {
|
||||
t1 := &Thing1{}
|
||||
t2 := t1
|
||||
t3 := &Thing1{}
|
||||
|
||||
pointer1 := reflect.ValueOf(t1).Pointer()
|
||||
|
||||
fail(t, so(t1, ShouldNotPointTo), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(t1, ShouldNotPointTo, t2, t3), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(t1, ShouldNotPointTo, t3))
|
||||
fail(t, so(t1, ShouldNotPointTo, t2), fmt.Sprintf("Expected '&{a:}' and '&{a:}' to be different references (but they matched: '%v')!", pointer1))
|
||||
|
||||
t4 := Thing1{}
|
||||
t5 := t4
|
||||
|
||||
fail(t, so(t4, ShouldNotPointTo, t5), "Both arguments should be pointers (the first was not)!")
|
||||
fail(t, so(&t4, ShouldNotPointTo, t5), "Both arguments should be pointers (the second was not)!")
|
||||
fail(t, so(nil, ShouldNotPointTo, nil), "Both arguments should be pointers (the first was nil)!")
|
||||
fail(t, so(&t4, ShouldNotPointTo, nil), "Both arguments should be pointers (the second was nil)!")
|
||||
}
|
||||
|
||||
func TestShouldBeNil(t *testing.T) {
|
||||
fail(t, so(nil, ShouldBeNil, nil, nil, nil), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(nil, ShouldBeNil, nil), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
|
||||
pass(t, so(nil, ShouldBeNil))
|
||||
fail(t, so(1, ShouldBeNil), "Expected: nil Actual: '1'")
|
||||
|
||||
var thing Thinger
|
||||
pass(t, so(thing, ShouldBeNil))
|
||||
thing = &Thing{}
|
||||
fail(t, so(thing, ShouldBeNil), "Expected: nil Actual: '&{}'")
|
||||
|
||||
var thingOne *Thing1
|
||||
pass(t, so(thingOne, ShouldBeNil))
|
||||
|
||||
var nilSlice []int = nil
|
||||
pass(t, so(nilSlice, ShouldBeNil))
|
||||
|
||||
var nilMap map[string]string = nil
|
||||
pass(t, so(nilMap, ShouldBeNil))
|
||||
|
||||
var nilChannel chan int = nil
|
||||
pass(t, so(nilChannel, ShouldBeNil))
|
||||
|
||||
var nilFunc func() = nil
|
||||
pass(t, so(nilFunc, ShouldBeNil))
|
||||
|
||||
var nilInterface interface{} = nil
|
||||
pass(t, so(nilInterface, ShouldBeNil))
|
||||
}
|
||||
|
||||
func TestShouldNotBeNil(t *testing.T) {
|
||||
fail(t, so(nil, ShouldNotBeNil, nil, nil, nil), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(nil, ShouldNotBeNil, nil), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
|
||||
fail(t, so(nil, ShouldNotBeNil), "Expected '<nil>' to NOT be nil (but it was)!")
|
||||
pass(t, so(1, ShouldNotBeNil))
|
||||
|
||||
var thing Thinger
|
||||
fail(t, so(thing, ShouldNotBeNil), "Expected '<nil>' to NOT be nil (but it was)!")
|
||||
thing = &Thing{}
|
||||
pass(t, so(thing, ShouldNotBeNil))
|
||||
}
|
||||
|
||||
func TestShouldBeTrue(t *testing.T) {
|
||||
fail(t, so(true, ShouldBeTrue, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(true, ShouldBeTrue, 1), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
|
||||
fail(t, so(false, ShouldBeTrue), "Expected: true Actual: false")
|
||||
fail(t, so(1, ShouldBeTrue), "Expected: true Actual: 1")
|
||||
pass(t, so(true, ShouldBeTrue))
|
||||
}
|
||||
|
||||
func TestShouldBeFalse(t *testing.T) {
|
||||
fail(t, so(false, ShouldBeFalse, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(false, ShouldBeFalse, 1), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
|
||||
fail(t, so(true, ShouldBeFalse), "Expected: false Actual: true")
|
||||
fail(t, so(1, ShouldBeFalse), "Expected: false Actual: 1")
|
||||
pass(t, so(false, ShouldBeFalse))
|
||||
}
|
||||
|
||||
func TestShouldBeZeroValue(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so(0, ShouldBeZeroValue, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(false, ShouldBeZeroValue, true), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
|
||||
fail(t, so(1, ShouldBeZeroValue), "0|1|'1' should have been the zero value") //"Expected: (zero value) Actual: 1")
|
||||
fail(t, so(true, ShouldBeZeroValue), "false|true|'true' should have been the zero value") //"Expected: (zero value) Actual: true")
|
||||
fail(t, so("123", ShouldBeZeroValue), "|123|'123' should have been the zero value") //"Expected: (zero value) Actual: 123")
|
||||
fail(t, so(" ", ShouldBeZeroValue), "| |' ' should have been the zero value") //"Expected: (zero value) Actual: ")
|
||||
fail(t, so([]string{"Nonempty"}, ShouldBeZeroValue), "[]|[Nonempty]|'[Nonempty]' should have been the zero value") //"Expected: (zero value) Actual: [Nonempty]")
|
||||
fail(t, so(struct{ a string }{a: "asdf"}, ShouldBeZeroValue), "{}|{asdf}|'{a:asdf}' should have been the zero value")
|
||||
pass(t, so(0, ShouldBeZeroValue))
|
||||
pass(t, so(false, ShouldBeZeroValue))
|
||||
pass(t, so("", ShouldBeZeroValue))
|
||||
pass(t, so(struct{}{}, ShouldBeZeroValue))
|
||||
}
|
22
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/filter.go
generated
vendored
22
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/filter.go
generated
vendored
@ -1,22 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
success = ""
|
||||
needExactValues = "This assertion requires exactly %d comparison values (you provided %d)."
|
||||
)
|
||||
|
||||
func need(needed int, expected []interface{}) string {
|
||||
if len(expected) != needed {
|
||||
return fmt.Sprintf(needExactValues, needed, len(expected))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func atLeast(minimum int, expected []interface{}) string {
|
||||
if len(expected) < 1 {
|
||||
return shouldHaveProvidedCollectionMembers
|
||||
}
|
||||
return success
|
||||
}
|
7
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/init.go
generated
vendored
7
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/init.go
generated
vendored
@ -1,7 +0,0 @@
|
||||
package assertions
|
||||
|
||||
var serializer Serializer
|
||||
|
||||
func init() {
|
||||
serializer = newSerializer()
|
||||
}
|
86
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/messages.go
generated
vendored
86
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/messages.go
generated
vendored
@ -1,86 +0,0 @@
|
||||
package assertions
|
||||
|
||||
const ( // equality
|
||||
shouldHaveBeenEqual = "Expected: '%v'\nActual: '%v'\n(Should be equal)"
|
||||
shouldNotHaveBeenEqual = "Expected '%v'\nto NOT equal '%v'\n(but it did)!"
|
||||
shouldHaveBeenAlmostEqual = "Expected '%v' to almost equal '%v' (but it didn't)!"
|
||||
shouldHaveNotBeenAlmostEqual = "Expected '%v' to NOT almost equal '%v' (but it did)!"
|
||||
shouldHaveResembled = "Expected: '%T(%+v)'\nActual: '%T(%+v)'\n(Should resemble)!"
|
||||
shouldNotHaveResembled = "Expected '%T(%+v)'\nto NOT resemble '%T(%+v)'\n(but it did)!"
|
||||
shouldBePointers = "Both arguments should be pointers "
|
||||
shouldHaveBeenNonNilPointer = shouldBePointers + "(the %s was %s)!"
|
||||
shouldHavePointedTo = "Expected '%+v' (address: '%v') and '%+v' (address: '%v') to be the same address (but their weren't)!"
|
||||
shouldNotHavePointedTo = "Expected '%+v' and '%+v' to be different references (but they matched: '%v')!"
|
||||
shouldHaveBeenNil = "Expected: nil\nActual: '%v'"
|
||||
shouldNotHaveBeenNil = "Expected '%+v' to NOT be nil (but it was)!"
|
||||
shouldHaveBeenTrue = "Expected: true\nActual: %v"
|
||||
shouldHaveBeenFalse = "Expected: false\nActual: %v"
|
||||
shouldHaveBeenZeroValue = "'%+v' should have been the zero value" //"Expected: (zero value)\nActual: %v"
|
||||
)
|
||||
|
||||
const ( // quantity comparisons
|
||||
shouldHaveBeenGreater = "Expected '%v' to be greater than '%v' (but it wasn't)!"
|
||||
shouldHaveBeenGreaterOrEqual = "Expected '%v' to be greater than or equal to '%v' (but it wasn't)!"
|
||||
shouldHaveBeenLess = "Expected '%v' to be less than '%v' (but it wasn't)!"
|
||||
shouldHaveBeenLessOrEqual = "Expected '%v' to be less than or equal to '%v' (but it wasn't)!"
|
||||
shouldHaveBeenBetween = "Expected '%v' to be between '%v' and '%v' (but it wasn't)!"
|
||||
shouldNotHaveBeenBetween = "Expected '%v' NOT to be between '%v' and '%v' (but it was)!"
|
||||
shouldHaveDifferentUpperAndLower = "The lower and upper bounds must be different values (they were both '%v')."
|
||||
shouldHaveBeenBetweenOrEqual = "Expected '%v' to be between '%v' and '%v' or equal to one of them (but it wasn't)!"
|
||||
shouldNotHaveBeenBetweenOrEqual = "Expected '%v' NOT to be between '%v' and '%v' or equal to one of them (but it was)!"
|
||||
)
|
||||
|
||||
const ( // collections
|
||||
shouldHaveContained = "Expected the container (%v) to contain: '%v' (but it didn't)!"
|
||||
shouldNotHaveContained = "Expected the container (%v) NOT to contain: '%v' (but it did)!"
|
||||
shouldHaveBeenIn = "Expected '%v' to be in the container (%v, but it wasn't)!"
|
||||
shouldNotHaveBeenIn = "Expected '%v' NOT to be in the container (%v, but it was)!"
|
||||
shouldHaveBeenAValidCollection = "You must provide a valid container (was %v)!"
|
||||
shouldHaveProvidedCollectionMembers = "This assertion requires at least 1 comparison value (you provided 0)."
|
||||
shouldHaveBeenEmpty = "Expected %+v to be empty (but it wasn't)!"
|
||||
shouldNotHaveBeenEmpty = "Expected %+v to NOT be empty (but it was)!"
|
||||
)
|
||||
|
||||
const ( // strings
|
||||
shouldHaveStartedWith = "Expected '%v'\nto start with '%v'\n(but it didn't)!"
|
||||
shouldNotHaveStartedWith = "Expected '%v'\nNOT to start with '%v'\n(but it did)!"
|
||||
shouldHaveEndedWith = "Expected '%v'\nto end with '%v'\n(but it didn't)!"
|
||||
shouldNotHaveEndedWith = "Expected '%v'\nNOT to end with '%v'\n(but it did)!"
|
||||
shouldBothBeStrings = "Both arguments to this assertion must be strings (you provided %v and %v)."
|
||||
shouldBeString = "The argument to this assertion must be a string (you provided %v)."
|
||||
shouldHaveContainedSubstring = "Expected '%s' to contain substring '%s' (but it didn't)!"
|
||||
shouldNotHaveContainedSubstring = "Expected '%s' NOT to contain substring '%s' (but it didn't)!"
|
||||
shouldHaveBeenBlank = "Expected '%s' to be blank (but it wasn't)!"
|
||||
shouldNotHaveBeenBlank = "Expected value to NOT be blank (but it was)!"
|
||||
)
|
||||
|
||||
const ( // panics
|
||||
shouldUseVoidNiladicFunction = "You must provide a void, niladic function as the first argument!"
|
||||
shouldHavePanickedWith = "Expected func() to panic with '%v' (but it panicked with '%v')!"
|
||||
shouldHavePanicked = "Expected func() to panic (but it didn't)!"
|
||||
shouldNotHavePanicked = "Expected func() NOT to panic (error: '%+v')!"
|
||||
shouldNotHavePanickedWith = "Expected func() NOT to panic with '%v' (but it did)!"
|
||||
)
|
||||
|
||||
const ( // type checking
|
||||
shouldHaveBeenA = "Expected '%v' to be: '%v' (but was: '%v')!"
|
||||
shouldNotHaveBeenA = "Expected '%v' to NOT be: '%v' (but it was)!"
|
||||
|
||||
shouldHaveImplemented = "Expected: '%v interface support'\nActual: '%v' does not implement the interface!"
|
||||
shouldNotHaveImplemented = "Expected '%v'\nto NOT implement '%v'\n(but it did)!"
|
||||
shouldCompareWithInterfacePointer = "The expected value must be a pointer to an interface type (eg. *fmt.Stringer)"
|
||||
shouldNotBeNilActual = "The actual value was 'nil' and should be a value or a pointer to a value!"
|
||||
)
|
||||
|
||||
const ( // time comparisons
|
||||
shouldUseTimes = "You must provide time instances as arguments to this assertion."
|
||||
shouldUseTimeSlice = "You must provide a slice of time instances as the first argument to this assertion."
|
||||
shouldUseDurationAndTime = "You must provide a duration and a time as arguments to this assertion."
|
||||
shouldHaveHappenedBefore = "Expected '%v' to happen before '%v' (it happened '%v' after)!"
|
||||
shouldHaveHappenedAfter = "Expected '%v' to happen after '%v' (it happened '%v' before)!"
|
||||
shouldHaveHappenedBetween = "Expected '%v' to happen between '%v' and '%v' (it happened '%v' outside threshold)!"
|
||||
shouldNotHaveHappenedOnOrBetween = "Expected '%v' to NOT happen on or between '%v' and '%v' (but it did)!"
|
||||
|
||||
// format params: incorrect-index, previous-index, previous-time, incorrect-index, incorrect-time
|
||||
shouldHaveBeenChronological = "The 'Time' at index [%d] should have happened after the previous one (but it didn't!):\n [%d]: %s\n [%d]: %s (see, it happened before!)"
|
||||
)
|
115
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic.go
generated
vendored
115
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic.go
generated
vendored
@ -1,115 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ShouldPanic receives a void, niladic function and expects to recover a panic.
|
||||
func ShouldPanic(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = shouldHavePanicked
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldNotPanic receives a void, niladic function and expects to execute the function without any panic.
|
||||
func ShouldNotPanic(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered != nil {
|
||||
message = fmt.Sprintf(shouldNotHavePanicked, recovered)
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldPanicWith receives a void, niladic function and expects to recover a panic with the second argument as the content.
|
||||
func ShouldPanicWith(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = shouldHavePanicked
|
||||
} else {
|
||||
if equal := ShouldEqual(recovered, expected[0]); equal != success {
|
||||
message = serializer.serialize(expected[0], recovered, fmt.Sprintf(shouldHavePanickedWith, expected[0], recovered))
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ShouldNotPanicWith receives a void, niladic function and expects to recover a panic whose content differs from the second argument.
|
||||
func ShouldNotPanicWith(actual interface{}, expected ...interface{}) (message string) {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
action, _ := actual.(func())
|
||||
|
||||
if action == nil {
|
||||
message = shouldUseVoidNiladicFunction
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
message = success
|
||||
} else {
|
||||
if equal := ShouldEqual(recovered, expected[0]); equal == success {
|
||||
message = fmt.Sprintf(shouldNotHavePanickedWith, expected[0])
|
||||
} else {
|
||||
message = success
|
||||
}
|
||||
}
|
||||
}()
|
||||
action()
|
||||
|
||||
return
|
||||
}
|
53
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic_test.go
generated
vendored
53
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/panic_test.go
generated
vendored
@ -1,53 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShouldPanic(t *testing.T) {
|
||||
fail(t, so(func() {}, ShouldPanic, 1), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
fail(t, so(func() {}, ShouldPanic, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(1, ShouldPanic), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func(i int) {}, ShouldPanic), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func() int { panic("hi") }, ShouldPanic), shouldUseVoidNiladicFunction)
|
||||
|
||||
fail(t, so(func() {}, ShouldPanic), shouldHavePanicked)
|
||||
pass(t, so(func() { panic("hi") }, ShouldPanic))
|
||||
}
|
||||
|
||||
func TestShouldNotPanic(t *testing.T) {
|
||||
fail(t, so(func() {}, ShouldNotPanic, 1), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
fail(t, so(func() {}, ShouldNotPanic, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(1, ShouldNotPanic), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func(i int) {}, ShouldNotPanic), shouldUseVoidNiladicFunction)
|
||||
|
||||
fail(t, so(func() { panic("hi") }, ShouldNotPanic), fmt.Sprintf(shouldNotHavePanicked, "hi"))
|
||||
pass(t, so(func() {}, ShouldNotPanic))
|
||||
}
|
||||
|
||||
func TestShouldPanicWith(t *testing.T) {
|
||||
fail(t, so(func() {}, ShouldPanicWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(func() {}, ShouldPanicWith, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(1, ShouldPanicWith, 1), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func(i int) {}, ShouldPanicWith, "hi"), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func() {}, ShouldPanicWith, "bye"), shouldHavePanicked)
|
||||
fail(t, so(func() { panic("hi") }, ShouldPanicWith, "bye"), "bye|hi|Expected func() to panic with 'bye' (but it panicked with 'hi')!")
|
||||
|
||||
pass(t, so(func() { panic("hi") }, ShouldPanicWith, "hi"))
|
||||
}
|
||||
|
||||
func TestShouldNotPanicWith(t *testing.T) {
|
||||
fail(t, so(func() {}, ShouldNotPanicWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(func() {}, ShouldNotPanicWith, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(1, ShouldNotPanicWith, 1), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func(i int) {}, ShouldNotPanicWith, "hi"), shouldUseVoidNiladicFunction)
|
||||
fail(t, so(func() { panic("hi") }, ShouldNotPanicWith, "hi"), "Expected func() NOT to panic with 'hi' (but it did)!")
|
||||
|
||||
pass(t, so(func() {}, ShouldNotPanicWith, "bye"))
|
||||
pass(t, so(func() { panic("hi") }, ShouldNotPanicWith, "bye"))
|
||||
}
|
141
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity.go
generated
vendored
141
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity.go
generated
vendored
@ -1,141 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jacobsa/oglematchers"
|
||||
)
|
||||
|
||||
// ShouldBeGreaterThan receives exactly two parameters and ensures that the first is greater than the second.
|
||||
func ShouldBeGreaterThan(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
if matchError := oglematchers.GreaterThan(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenGreater, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeGreaterThanOrEqualTo receives exactly two parameters and ensures that the first is greater than or equal to the second.
|
||||
func ShouldBeGreaterThanOrEqualTo(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.GreaterOrEqual(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenGreaterOrEqual, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than the second.
|
||||
func ShouldBeLessThan(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.LessThan(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeLessThan receives exactly two parameters and ensures that the first is less than or equal to the second.
|
||||
func ShouldBeLessThanOrEqualTo(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
} else if matchError := oglematchers.LessOrEqual(expected[0]).Matches(actual); matchError != nil {
|
||||
return fmt.Sprintf(shouldHaveBeenLess, actual, expected[0])
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is between both bounds (but not equal to either of them).
|
||||
func ShouldBeBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if !isBetween(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldHaveBeenBetween, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBetween receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is NOT between both bounds.
|
||||
func ShouldNotBeBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if isBetween(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldNotHaveBeenBetween, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
func deriveBounds(values []interface{}) (lower interface{}, upper interface{}, fail string) {
|
||||
lower = values[0]
|
||||
upper = values[1]
|
||||
|
||||
if ShouldNotEqual(lower, upper) != success {
|
||||
return nil, nil, fmt.Sprintf(shouldHaveDifferentUpperAndLower, lower)
|
||||
} else if ShouldBeLessThan(lower, upper) != success {
|
||||
lower, upper = upper, lower
|
||||
}
|
||||
return lower, upper, success
|
||||
}
|
||||
func isBetween(value, lower, upper interface{}) bool {
|
||||
if ShouldBeGreaterThan(value, lower) != success {
|
||||
return false
|
||||
} else if ShouldBeLessThan(value, upper) != success {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ShouldBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is between both bounds or equal to one of them.
|
||||
func ShouldBeBetweenOrEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if !isBetweenOrEqual(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldHaveBeenBetweenOrEqual, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBetweenOrEqual receives exactly three parameters: an actual value, a lower bound, and an upper bound.
|
||||
// It ensures that the actual value is nopt between the bounds nor equal to either of them.
|
||||
func ShouldNotBeBetweenOrEqual(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
lower, upper, fail := deriveBounds(expected)
|
||||
|
||||
if fail != success {
|
||||
return fail
|
||||
} else if isBetweenOrEqual(actual, lower, upper) {
|
||||
return fmt.Sprintf(shouldNotHaveBeenBetweenOrEqual, actual, lower, upper)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func isBetweenOrEqual(value, lower, upper interface{}) bool {
|
||||
if ShouldBeGreaterThanOrEqualTo(value, lower) != success {
|
||||
return false
|
||||
} else if ShouldBeLessThanOrEqualTo(value, upper) != success {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
145
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity_test.go
generated
vendored
145
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/quantity_test.go
generated
vendored
@ -1,145 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestShouldBeGreaterThan(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeGreaterThan), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeGreaterThan, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(1, ShouldBeGreaterThan, 0))
|
||||
pass(t, so(1.1, ShouldBeGreaterThan, 1))
|
||||
pass(t, so(1, ShouldBeGreaterThan, uint(0)))
|
||||
pass(t, so("b", ShouldBeGreaterThan, "a"))
|
||||
|
||||
fail(t, so(0, ShouldBeGreaterThan, 1), "Expected '0' to be greater than '1' (but it wasn't)!")
|
||||
fail(t, so(1, ShouldBeGreaterThan, 1.1), "Expected '1' to be greater than '1.1' (but it wasn't)!")
|
||||
fail(t, so(uint(0), ShouldBeGreaterThan, 1.1), "Expected '0' to be greater than '1.1' (but it wasn't)!")
|
||||
fail(t, so("a", ShouldBeGreaterThan, "b"), "Expected 'a' to be greater than 'b' (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldBeGreaterThanOrEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeGreaterThanOrEqualTo), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeGreaterThanOrEqualTo, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(1, ShouldBeGreaterThanOrEqualTo, 1))
|
||||
pass(t, so(1.1, ShouldBeGreaterThanOrEqualTo, 1.1))
|
||||
pass(t, so(1, ShouldBeGreaterThanOrEqualTo, uint(1)))
|
||||
pass(t, so("b", ShouldBeGreaterThanOrEqualTo, "b"))
|
||||
|
||||
pass(t, so(1, ShouldBeGreaterThanOrEqualTo, 0))
|
||||
pass(t, so(1.1, ShouldBeGreaterThanOrEqualTo, 1))
|
||||
pass(t, so(1, ShouldBeGreaterThanOrEqualTo, uint(0)))
|
||||
pass(t, so("b", ShouldBeGreaterThanOrEqualTo, "a"))
|
||||
|
||||
fail(t, so(0, ShouldBeGreaterThanOrEqualTo, 1), "Expected '0' to be greater than or equal to '1' (but it wasn't)!")
|
||||
fail(t, so(1, ShouldBeGreaterThanOrEqualTo, 1.1), "Expected '1' to be greater than or equal to '1.1' (but it wasn't)!")
|
||||
fail(t, so(uint(0), ShouldBeGreaterThanOrEqualTo, 1.1), "Expected '0' to be greater than or equal to '1.1' (but it wasn't)!")
|
||||
fail(t, so("a", ShouldBeGreaterThanOrEqualTo, "b"), "Expected 'a' to be greater than or equal to 'b' (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldBeLessThan(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeLessThan), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeLessThan, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(0, ShouldBeLessThan, 1))
|
||||
pass(t, so(1, ShouldBeLessThan, 1.1))
|
||||
pass(t, so(uint(0), ShouldBeLessThan, 1))
|
||||
pass(t, so("a", ShouldBeLessThan, "b"))
|
||||
|
||||
fail(t, so(1, ShouldBeLessThan, 0), "Expected '1' to be less than '0' (but it wasn't)!")
|
||||
fail(t, so(1.1, ShouldBeLessThan, 1), "Expected '1.1' to be less than '1' (but it wasn't)!")
|
||||
fail(t, so(1.1, ShouldBeLessThan, uint(0)), "Expected '1.1' to be less than '0' (but it wasn't)!")
|
||||
fail(t, so("b", ShouldBeLessThan, "a"), "Expected 'b' to be less than 'a' (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldBeLessThanOrEqualTo(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeLessThanOrEqualTo), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeLessThanOrEqualTo, 0, 0), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so(1, ShouldBeLessThanOrEqualTo, 1))
|
||||
pass(t, so(1.1, ShouldBeLessThanOrEqualTo, 1.1))
|
||||
pass(t, so(uint(1), ShouldBeLessThanOrEqualTo, 1))
|
||||
pass(t, so("b", ShouldBeLessThanOrEqualTo, "b"))
|
||||
|
||||
pass(t, so(0, ShouldBeLessThanOrEqualTo, 1))
|
||||
pass(t, so(1, ShouldBeLessThanOrEqualTo, 1.1))
|
||||
pass(t, so(uint(0), ShouldBeLessThanOrEqualTo, 1))
|
||||
pass(t, so("a", ShouldBeLessThanOrEqualTo, "b"))
|
||||
|
||||
fail(t, so(1, ShouldBeLessThanOrEqualTo, 0), "Expected '1' to be less than '0' (but it wasn't)!")
|
||||
fail(t, so(1.1, ShouldBeLessThanOrEqualTo, 1), "Expected '1.1' to be less than '1' (but it wasn't)!")
|
||||
fail(t, so(1.1, ShouldBeLessThanOrEqualTo, uint(0)), "Expected '1.1' to be less than '0' (but it wasn't)!")
|
||||
fail(t, so("b", ShouldBeLessThanOrEqualTo, "a"), "Expected 'b' to be less than 'a' (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldBeBetween(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(4, ShouldBeBetween, 1, 1), "The lower and upper bounds must be different values (they were both '1').")
|
||||
|
||||
fail(t, so(7, ShouldBeBetween, 8, 12), "Expected '7' to be between '8' and '12' (but it wasn't)!")
|
||||
fail(t, so(8, ShouldBeBetween, 8, 12), "Expected '8' to be between '8' and '12' (but it wasn't)!")
|
||||
pass(t, so(9, ShouldBeBetween, 8, 12))
|
||||
pass(t, so(10, ShouldBeBetween, 8, 12))
|
||||
pass(t, so(11, ShouldBeBetween, 8, 12))
|
||||
fail(t, so(12, ShouldBeBetween, 8, 12), "Expected '12' to be between '8' and '12' (but it wasn't)!")
|
||||
fail(t, so(13, ShouldBeBetween, 8, 12), "Expected '13' to be between '8' and '12' (but it wasn't)!")
|
||||
|
||||
pass(t, so(1, ShouldBeBetween, 2, 0))
|
||||
fail(t, so(-1, ShouldBeBetween, 2, 0), "Expected '-1' to be between '0' and '2' (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldNotBeBetween(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotBeBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldNotBeBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(4, ShouldNotBeBetween, 1, 1), "The lower and upper bounds must be different values (they were both '1').")
|
||||
|
||||
pass(t, so(7, ShouldNotBeBetween, 8, 12))
|
||||
pass(t, so(8, ShouldNotBeBetween, 8, 12))
|
||||
fail(t, so(9, ShouldNotBeBetween, 8, 12), "Expected '9' NOT to be between '8' and '12' (but it was)!")
|
||||
fail(t, so(10, ShouldNotBeBetween, 8, 12), "Expected '10' NOT to be between '8' and '12' (but it was)!")
|
||||
fail(t, so(11, ShouldNotBeBetween, 8, 12), "Expected '11' NOT to be between '8' and '12' (but it was)!")
|
||||
pass(t, so(12, ShouldNotBeBetween, 8, 12))
|
||||
pass(t, so(13, ShouldNotBeBetween, 8, 12))
|
||||
|
||||
pass(t, so(-1, ShouldNotBeBetween, 2, 0))
|
||||
fail(t, so(1, ShouldNotBeBetween, 2, 0), "Expected '1' NOT to be between '0' and '2' (but it was)!")
|
||||
}
|
||||
|
||||
func TestShouldBeBetweenOrEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldBeBetweenOrEqual), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldBeBetweenOrEqual, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(4, ShouldBeBetweenOrEqual, 1, 1), "The lower and upper bounds must be different values (they were both '1').")
|
||||
|
||||
fail(t, so(7, ShouldBeBetweenOrEqual, 8, 12), "Expected '7' to be between '8' and '12' or equal to one of them (but it wasn't)!")
|
||||
pass(t, so(8, ShouldBeBetweenOrEqual, 8, 12))
|
||||
pass(t, so(9, ShouldBeBetweenOrEqual, 8, 12))
|
||||
pass(t, so(10, ShouldBeBetweenOrEqual, 8, 12))
|
||||
pass(t, so(11, ShouldBeBetweenOrEqual, 8, 12))
|
||||
pass(t, so(12, ShouldBeBetweenOrEqual, 8, 12))
|
||||
fail(t, so(13, ShouldBeBetweenOrEqual, 8, 12), "Expected '13' to be between '8' and '12' or equal to one of them (but it wasn't)!")
|
||||
|
||||
pass(t, so(1, ShouldBeBetweenOrEqual, 2, 0))
|
||||
fail(t, so(-1, ShouldBeBetweenOrEqual, 2, 0), "Expected '-1' to be between '0' and '2' or equal to one of them (but it wasn't)!")
|
||||
}
|
||||
|
||||
func TestShouldNotBeBetweenOrEqual(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotBeBetweenOrEqual), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldNotBeBetweenOrEqual, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(4, ShouldNotBeBetweenOrEqual, 1, 1), "The lower and upper bounds must be different values (they were both '1').")
|
||||
|
||||
pass(t, so(7, ShouldNotBeBetweenOrEqual, 8, 12))
|
||||
fail(t, so(8, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '8' NOT to be between '8' and '12' or equal to one of them (but it was)!")
|
||||
fail(t, so(9, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '9' NOT to be between '8' and '12' or equal to one of them (but it was)!")
|
||||
fail(t, so(10, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '10' NOT to be between '8' and '12' or equal to one of them (but it was)!")
|
||||
fail(t, so(11, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '11' NOT to be between '8' and '12' or equal to one of them (but it was)!")
|
||||
fail(t, so(12, ShouldNotBeBetweenOrEqual, 8, 12), "Expected '12' NOT to be between '8' and '12' or equal to one of them (but it was)!")
|
||||
pass(t, so(13, ShouldNotBeBetweenOrEqual, 8, 12))
|
||||
|
||||
pass(t, so(-1, ShouldNotBeBetweenOrEqual, 2, 0))
|
||||
fail(t, so(1, ShouldNotBeBetweenOrEqual, 2, 0), "Expected '1' NOT to be between '0' and '2' or equal to one of them (but it was)!")
|
||||
}
|
31
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/serializer.go
generated
vendored
31
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/serializer.go
generated
vendored
@ -1,31 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type Serializer interface {
|
||||
serialize(expected, actual interface{}, message string) string
|
||||
}
|
||||
|
||||
type failureSerializer struct{}
|
||||
|
||||
func (self *failureSerializer) serialize(expected, actual interface{}, message string) string {
|
||||
view := reporting.FailureView{
|
||||
Message: message,
|
||||
Expected: fmt.Sprintf("%+v", expected),
|
||||
Actual: fmt.Sprintf("%+v", actual),
|
||||
}
|
||||
serialized, err := json.Marshal(view)
|
||||
if err != nil {
|
||||
return message
|
||||
}
|
||||
return string(serialized)
|
||||
}
|
||||
|
||||
func newSerializer() *failureSerializer {
|
||||
return &failureSerializer{}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
func TestSerializerCreatesSerializedVersionOfAssertionResult(t *testing.T) {
|
||||
thing1 := Thing1{"Hi"}
|
||||
thing2 := Thing2{"Bye"}
|
||||
message := "Super-hip failure message."
|
||||
serializer := newSerializer()
|
||||
|
||||
actualResult := serializer.serialize(thing1, thing2, message)
|
||||
|
||||
expectedResult, _ := json.Marshal(reporting.FailureView{
|
||||
Message: message,
|
||||
Expected: fmt.Sprintf("%+v", thing1),
|
||||
Actual: fmt.Sprintf("%+v", thing2),
|
||||
})
|
||||
|
||||
if actualResult != string(expectedResult) {
|
||||
t.Errorf("\nExpected: %s\nActual: %s", string(expectedResult), actualResult)
|
||||
}
|
||||
}
|
183
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings.go
generated
vendored
183
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings.go
generated
vendored
@ -1,183 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ShouldStartWith receives exactly 2 string parameters and ensures that the first starts with the second.
|
||||
func ShouldStartWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
prefix, prefixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !prefixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldStartWith(value, prefix)
|
||||
}
|
||||
func shouldStartWith(value, prefix string) string {
|
||||
if !strings.HasPrefix(value, prefix) {
|
||||
shortval := value
|
||||
if len(shortval) > len(prefix) {
|
||||
shortval = shortval[:len(prefix)] + "..."
|
||||
}
|
||||
return serializer.serialize(prefix, shortval, fmt.Sprintf(shouldHaveStartedWith, value, prefix))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotStartWith receives exactly 2 string parameters and ensures that the first does not start with the second.
|
||||
func ShouldNotStartWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
prefix, prefixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !prefixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldNotStartWith(value, prefix)
|
||||
}
|
||||
func shouldNotStartWith(value, prefix string) string {
|
||||
if strings.HasPrefix(value, prefix) {
|
||||
if value == "" {
|
||||
value = "<empty>"
|
||||
}
|
||||
if prefix == "" {
|
||||
prefix = "<empty>"
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveStartedWith, value, prefix)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldEndWith receives exactly 2 string parameters and ensures that the first ends with the second.
|
||||
func ShouldEndWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
suffix, suffixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !suffixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldEndWith(value, suffix)
|
||||
}
|
||||
func shouldEndWith(value, suffix string) string {
|
||||
if !strings.HasSuffix(value, suffix) {
|
||||
shortval := value
|
||||
if len(shortval) > len(suffix) {
|
||||
shortval = "..." + shortval[len(shortval)-len(suffix):]
|
||||
}
|
||||
return serializer.serialize(suffix, shortval, fmt.Sprintf(shouldHaveEndedWith, value, suffix))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldEndWith receives exactly 2 string parameters and ensures that the first does not end with the second.
|
||||
func ShouldNotEndWith(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
value, valueIsString := actual.(string)
|
||||
suffix, suffixIsString := expected[0].(string)
|
||||
|
||||
if !valueIsString || !suffixIsString {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
return shouldNotEndWith(value, suffix)
|
||||
}
|
||||
func shouldNotEndWith(value, suffix string) string {
|
||||
if strings.HasSuffix(value, suffix) {
|
||||
if value == "" {
|
||||
value = "<empty>"
|
||||
}
|
||||
if suffix == "" {
|
||||
suffix = "<empty>"
|
||||
}
|
||||
return fmt.Sprintf(shouldNotHaveEndedWith, value, suffix)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldContainSubstring receives exactly 2 string parameters and ensures that the first contains the second as a substring.
|
||||
func ShouldContainSubstring(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
long, longOk := actual.(string)
|
||||
short, shortOk := expected[0].(string)
|
||||
|
||||
if !longOk || !shortOk {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
if !strings.Contains(long, short) {
|
||||
return serializer.serialize(expected[0], actual, fmt.Sprintf(shouldHaveContainedSubstring, long, short))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotContainSubstring receives exactly 2 string parameters and ensures that the first does NOT contain the second as a substring.
|
||||
func ShouldNotContainSubstring(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
long, longOk := actual.(string)
|
||||
short, shortOk := expected[0].(string)
|
||||
|
||||
if !longOk || !shortOk {
|
||||
return fmt.Sprintf(shouldBothBeStrings, reflect.TypeOf(actual), reflect.TypeOf(expected[0]))
|
||||
}
|
||||
|
||||
if strings.Contains(long, short) {
|
||||
return fmt.Sprintf(shouldNotHaveContainedSubstring, long, short)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldBeBlank receives exactly 1 string parameter and ensures that it is equal to "".
|
||||
func ShouldBeBlank(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
value, ok := actual.(string)
|
||||
if !ok {
|
||||
return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual))
|
||||
}
|
||||
if value != "" {
|
||||
return serializer.serialize("", value, fmt.Sprintf(shouldHaveBeenBlank, value))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotBeBlank receives exactly 1 string parameter and ensures that it is equal to "".
|
||||
func ShouldNotBeBlank(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
value, ok := actual.(string)
|
||||
if !ok {
|
||||
return fmt.Sprintf(shouldBeString, reflect.TypeOf(actual))
|
||||
}
|
||||
if value == "" {
|
||||
return shouldNotHaveBeenBlank
|
||||
}
|
||||
return success
|
||||
}
|
102
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings_test.go
generated
vendored
102
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/strings_test.go
generated
vendored
@ -1,102 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestShouldStartWith(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so("", ShouldStartWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("", ShouldStartWith, "asdf", "asdf"), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so("", ShouldStartWith, ""))
|
||||
fail(t, so("", ShouldStartWith, "x"), "x||Expected '' to start with 'x' (but it didn't)!")
|
||||
pass(t, so("abc", ShouldStartWith, "abc"))
|
||||
fail(t, so("abc", ShouldStartWith, "abcd"), "abcd|abc|Expected 'abc' to start with 'abcd' (but it didn't)!")
|
||||
|
||||
pass(t, so("superman", ShouldStartWith, "super"))
|
||||
fail(t, so("superman", ShouldStartWith, "bat"), "bat|sup...|Expected 'superman' to start with 'bat' (but it didn't)!")
|
||||
fail(t, so("superman", ShouldStartWith, "man"), "man|sup...|Expected 'superman' to start with 'man' (but it didn't)!")
|
||||
|
||||
fail(t, so(1, ShouldStartWith, 2), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
}
|
||||
|
||||
func TestShouldNotStartWith(t *testing.T) {
|
||||
fail(t, so("", ShouldNotStartWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("", ShouldNotStartWith, "asdf", "asdf"), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
fail(t, so("", ShouldNotStartWith, ""), "Expected '<empty>' NOT to start with '<empty>' (but it did)!")
|
||||
fail(t, so("superman", ShouldNotStartWith, "super"), "Expected 'superman' NOT to start with 'super' (but it did)!")
|
||||
pass(t, so("superman", ShouldNotStartWith, "bat"))
|
||||
pass(t, so("superman", ShouldNotStartWith, "man"))
|
||||
|
||||
fail(t, so(1, ShouldNotStartWith, 2), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
}
|
||||
|
||||
func TestShouldEndWith(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so("", ShouldEndWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("", ShouldEndWith, "", ""), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
pass(t, so("", ShouldEndWith, ""))
|
||||
fail(t, so("", ShouldEndWith, "z"), "z||Expected '' to end with 'z' (but it didn't)!")
|
||||
pass(t, so("xyz", ShouldEndWith, "xyz"))
|
||||
fail(t, so("xyz", ShouldEndWith, "wxyz"), "wxyz|xyz|Expected 'xyz' to end with 'wxyz' (but it didn't)!")
|
||||
|
||||
pass(t, so("superman", ShouldEndWith, "man"))
|
||||
fail(t, so("superman", ShouldEndWith, "super"), "super|...erman|Expected 'superman' to end with 'super' (but it didn't)!")
|
||||
fail(t, so("superman", ShouldEndWith, "blah"), "blah|...rman|Expected 'superman' to end with 'blah' (but it didn't)!")
|
||||
|
||||
fail(t, so(1, ShouldEndWith, 2), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
}
|
||||
|
||||
func TestShouldNotEndWith(t *testing.T) {
|
||||
fail(t, so("", ShouldNotEndWith), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("", ShouldNotEndWith, "", ""), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
|
||||
fail(t, so("", ShouldNotEndWith, ""), "Expected '<empty>' NOT to end with '<empty>' (but it did)!")
|
||||
fail(t, so("superman", ShouldNotEndWith, "man"), "Expected 'superman' NOT to end with 'man' (but it did)!")
|
||||
pass(t, so("superman", ShouldNotEndWith, "super"))
|
||||
|
||||
fail(t, so(1, ShouldNotEndWith, 2), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
}
|
||||
|
||||
func TestShouldContainSubstring(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so("asdf", ShouldContainSubstring), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("asdf", ShouldContainSubstring, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(123, ShouldContainSubstring, 23), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
|
||||
pass(t, so("asdf", ShouldContainSubstring, "sd"))
|
||||
fail(t, so("qwer", ShouldContainSubstring, "sd"), "sd|qwer|Expected 'qwer' to contain substring 'sd' (but it didn't)!")
|
||||
}
|
||||
|
||||
func TestShouldNotContainSubstring(t *testing.T) {
|
||||
fail(t, so("asdf", ShouldNotContainSubstring), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so("asdf", ShouldNotContainSubstring, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(123, ShouldNotContainSubstring, 23), "Both arguments to this assertion must be strings (you provided int and int).")
|
||||
|
||||
pass(t, so("qwer", ShouldNotContainSubstring, "sd"))
|
||||
fail(t, so("asdf", ShouldNotContainSubstring, "sd"), "Expected 'asdf' NOT to contain substring 'sd' (but it didn't)!")
|
||||
}
|
||||
|
||||
func TestShouldBeBlank(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so("", ShouldBeBlank, "adsf"), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
fail(t, so(1, ShouldBeBlank), "The argument to this assertion must be a string (you provided int).")
|
||||
|
||||
fail(t, so("asdf", ShouldBeBlank), "|asdf|Expected 'asdf' to be blank (but it wasn't)!")
|
||||
pass(t, so("", ShouldBeBlank))
|
||||
}
|
||||
|
||||
func TestShouldNotBeBlank(t *testing.T) {
|
||||
fail(t, so("", ShouldNotBeBlank, "adsf"), "This assertion requires exactly 0 comparison values (you provided 1).")
|
||||
fail(t, so(1, ShouldNotBeBlank), "The argument to this assertion must be a string (you provided int).")
|
||||
|
||||
fail(t, so("", ShouldNotBeBlank), "Expected value to NOT be blank (but it was)!")
|
||||
pass(t, so("asdf", ShouldNotBeBlank))
|
||||
}
|
202
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time.go
generated
vendored
202
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time.go
generated
vendored
@ -1,202 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ShouldHappenBefore receives exactly 2 time.Time arguments and asserts that the first happens before the second.
|
||||
func ShouldHappenBefore(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if !actualTime.Before(expectedTime) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBefore, actualTime, expectedTime, actualTime.Sub(expectedTime))
|
||||
}
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrBefore receives exactly 2 time.Time arguments and asserts that the first happens on or before the second.
|
||||
func ShouldHappenOnOrBefore(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if actualTime.Equal(expectedTime) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenBefore(actualTime, expectedTime)
|
||||
}
|
||||
|
||||
// ShouldHappenAfter receives exactly 2 time.Time arguments and asserts that the first happens after the second.
|
||||
func ShouldHappenAfter(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if !actualTime.After(expectedTime) {
|
||||
return fmt.Sprintf(shouldHaveHappenedAfter, actualTime, expectedTime, expectedTime.Sub(actualTime))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrAfter receives exactly 2 time.Time arguments and asserts that the first happens on or after the second.
|
||||
func ShouldHappenOnOrAfter(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
expectedTime, secondOk := expected[0].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(expectedTime) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenAfter(actualTime, expectedTime)
|
||||
}
|
||||
|
||||
// ShouldHappenBetween receives exactly 3 time.Time arguments and asserts that the first happens between (not on) the second and third.
|
||||
func ShouldHappenBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
|
||||
if !actualTime.After(min) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, min.Sub(actualTime))
|
||||
}
|
||||
if !actualTime.Before(max) {
|
||||
return fmt.Sprintf(shouldHaveHappenedBetween, actualTime, min, max, actualTime.Sub(max))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first happens between or on the second and third.
|
||||
func ShouldHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(min) || actualTime.Equal(max) {
|
||||
return success
|
||||
}
|
||||
return ShouldHappenBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldNotHappenOnOrBetween receives exactly 3 time.Time arguments and asserts that the first
|
||||
// does NOT happen between or on the second or third.
|
||||
func ShouldNotHappenOnOrBetween(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
min, secondOk := expected[0].(time.Time)
|
||||
max, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseTimes
|
||||
}
|
||||
if actualTime.Equal(min) || actualTime.Equal(max) {
|
||||
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
|
||||
}
|
||||
if actualTime.After(min) && actualTime.Before(max) {
|
||||
return fmt.Sprintf(shouldNotHaveHappenedOnOrBetween, actualTime, min, max)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
|
||||
// and asserts that the first time.Time happens within or on the duration specified relative to
|
||||
// the other time.Time.
|
||||
func ShouldHappenWithin(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
tolerance, secondOk := expected[0].(time.Duration)
|
||||
threshold, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseDurationAndTime
|
||||
}
|
||||
|
||||
min := threshold.Add(-tolerance)
|
||||
max := threshold.Add(tolerance)
|
||||
return ShouldHappenOnOrBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldNotHappenWithin receives a time.Time, a time.Duration, and a time.Time (3 arguments)
|
||||
// and asserts that the first time.Time does NOT happen within or on the duration specified relative to
|
||||
// the other time.Time.
|
||||
func ShouldNotHappenWithin(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(2, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
actualTime, firstOk := actual.(time.Time)
|
||||
tolerance, secondOk := expected[0].(time.Duration)
|
||||
threshold, thirdOk := expected[1].(time.Time)
|
||||
|
||||
if !firstOk || !secondOk || !thirdOk {
|
||||
return shouldUseDurationAndTime
|
||||
}
|
||||
|
||||
min := threshold.Add(-tolerance)
|
||||
max := threshold.Add(tolerance)
|
||||
return ShouldNotHappenOnOrBetween(actualTime, min, max)
|
||||
}
|
||||
|
||||
// ShouldBeChronological receives a []time.Time slice and asserts that the are
|
||||
// in chronological order starting with the first time.Time as the earliest.
|
||||
func ShouldBeChronological(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(0, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
times, ok := actual.([]time.Time)
|
||||
if !ok {
|
||||
return shouldUseTimeSlice
|
||||
}
|
||||
|
||||
var previous time.Time
|
||||
for i, current := range times {
|
||||
if i > 0 && current.Before(previous) {
|
||||
return fmt.Sprintf(shouldHaveBeenChronological,
|
||||
i, i-1, previous.String(), i, current.String())
|
||||
}
|
||||
previous = current
|
||||
}
|
||||
return ""
|
||||
}
|
159
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time_test.go
generated
vendored
159
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/time_test.go
generated
vendored
@ -1,159 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestShouldHappenBefore(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenBefore), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenBefore, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenBefore, 1), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenBefore, time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenBefore, 0), shouldUseTimes)
|
||||
|
||||
fail(t, so(january3, ShouldHappenBefore, january1), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '48h0m0s' after)!", pretty(january3), pretty(january1)))
|
||||
fail(t, so(january3, ShouldHappenBefore, january3), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '0' after)!", pretty(january3), pretty(january3)))
|
||||
pass(t, so(january1, ShouldHappenBefore, january3))
|
||||
}
|
||||
|
||||
func TestShouldHappenOnOrBefore(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenOnOrBefore), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenOnOrBefore, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenOnOrBefore, 1), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenOnOrBefore, time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenOnOrBefore, 0), shouldUseTimes)
|
||||
|
||||
fail(t, so(january3, ShouldHappenOnOrBefore, january1), fmt.Sprintf("Expected '%s' to happen before '%s' (it happened '48h0m0s' after)!", pretty(january3), pretty(january1)))
|
||||
pass(t, so(january3, ShouldHappenOnOrBefore, january3))
|
||||
pass(t, so(january1, ShouldHappenOnOrBefore, january3))
|
||||
}
|
||||
|
||||
func TestShouldHappenAfter(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenAfter), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenAfter, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenAfter, 1), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenAfter, time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenAfter, 0), shouldUseTimes)
|
||||
|
||||
fail(t, so(january1, ShouldHappenAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2)))
|
||||
fail(t, so(january1, ShouldHappenAfter, january1), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '0' before)!", pretty(january1), pretty(january1)))
|
||||
pass(t, so(january3, ShouldHappenAfter, january1))
|
||||
}
|
||||
|
||||
func TestShouldHappenOnOrAfter(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenOnOrAfter), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenOnOrAfter, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenOnOrAfter, 1), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenOnOrAfter, time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenOnOrAfter, 0), shouldUseTimes)
|
||||
|
||||
fail(t, so(january1, ShouldHappenOnOrAfter, january2), fmt.Sprintf("Expected '%s' to happen after '%s' (it happened '24h0m0s' before)!", pretty(january1), pretty(january2)))
|
||||
pass(t, so(january1, ShouldHappenOnOrAfter, january1))
|
||||
pass(t, so(january3, ShouldHappenOnOrAfter, january1))
|
||||
}
|
||||
|
||||
func TestShouldHappenBetween(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenBetween, 1, 2), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenBetween, time.Now(), time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenBetween, 0, time.Now()), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenBetween, time.Now(), 9), shouldUseTimes)
|
||||
|
||||
fail(t, so(january1, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january2, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january2), pretty(january2), pretty(january4)))
|
||||
pass(t, so(january3, ShouldHappenBetween, january2, january4))
|
||||
fail(t, so(january4, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '0' outside threshold)!", pretty(january4), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january5, ShouldHappenBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
|
||||
}
|
||||
|
||||
func TestShouldHappenOnOrBetween(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenOnOrBetween, 1, time.Now()), shouldUseTimes)
|
||||
fail(t, so(0, ShouldHappenOnOrBetween, time.Now(), 1), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldHappenOnOrBetween, 0, 1), shouldUseTimes)
|
||||
|
||||
fail(t, so(january1, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
|
||||
pass(t, so(january2, ShouldHappenOnOrBetween, january2, january4))
|
||||
pass(t, so(january3, ShouldHappenOnOrBetween, january2, january4))
|
||||
pass(t, so(january4, ShouldHappenOnOrBetween, january2, january4))
|
||||
fail(t, so(january5, ShouldHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
|
||||
}
|
||||
|
||||
func TestShouldNotHappenOnOrBetween(t *testing.T) {
|
||||
fail(t, so(0, ShouldNotHappenOnOrBetween), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldNotHappenOnOrBetween, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldNotHappenOnOrBetween, 1, time.Now()), shouldUseTimes)
|
||||
fail(t, so(0, ShouldNotHappenOnOrBetween, time.Now(), 1), shouldUseTimes)
|
||||
fail(t, so(time.Now(), ShouldNotHappenOnOrBetween, 0, 1), shouldUseTimes)
|
||||
|
||||
pass(t, so(january1, ShouldNotHappenOnOrBetween, january2, january4))
|
||||
fail(t, so(january2, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january3, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january4, ShouldNotHappenOnOrBetween, january2, january4), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4)))
|
||||
pass(t, so(january5, ShouldNotHappenOnOrBetween, january2, january4))
|
||||
}
|
||||
|
||||
func TestShouldHappenWithin(t *testing.T) {
|
||||
fail(t, so(0, ShouldHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldHappenWithin, 1, 2), shouldUseDurationAndTime)
|
||||
fail(t, so(0, ShouldHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime)
|
||||
fail(t, so(time.Now(), ShouldHappenWithin, 0, time.Now()), shouldUseDurationAndTime)
|
||||
|
||||
fail(t, so(january1, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january1), pretty(january2), pretty(january4)))
|
||||
pass(t, so(january2, ShouldHappenWithin, oneDay, january3))
|
||||
pass(t, so(january3, ShouldHappenWithin, oneDay, january3))
|
||||
pass(t, so(january4, ShouldHappenWithin, oneDay, january3))
|
||||
fail(t, so(january5, ShouldHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to happen between '%s' and '%s' (it happened '24h0m0s' outside threshold)!", pretty(january5), pretty(january2), pretty(january4)))
|
||||
}
|
||||
|
||||
func TestShouldNotHappenWithin(t *testing.T) {
|
||||
fail(t, so(0, ShouldNotHappenWithin), "This assertion requires exactly 2 comparison values (you provided 0).")
|
||||
fail(t, so(0, ShouldNotHappenWithin, 1, 2, 3), "This assertion requires exactly 2 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(0, ShouldNotHappenWithin, 1, 2), shouldUseDurationAndTime)
|
||||
fail(t, so(0, ShouldNotHappenWithin, oneDay, time.Now()), shouldUseDurationAndTime)
|
||||
fail(t, so(time.Now(), ShouldNotHappenWithin, 0, time.Now()), shouldUseDurationAndTime)
|
||||
|
||||
pass(t, so(january1, ShouldNotHappenWithin, oneDay, january3))
|
||||
fail(t, so(january2, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january2), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january3, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january3), pretty(january2), pretty(january4)))
|
||||
fail(t, so(january4, ShouldNotHappenWithin, oneDay, january3), fmt.Sprintf("Expected '%s' to NOT happen on or between '%s' and '%s' (but it did)!", pretty(january4), pretty(january2), pretty(january4)))
|
||||
pass(t, so(january5, ShouldNotHappenWithin, oneDay, january3))
|
||||
}
|
||||
|
||||
func TestShouldBeChronological(t *testing.T) {
|
||||
fail(t, so(0, ShouldBeChronological, 1, 2, 3), "This assertion requires exactly 0 comparison values (you provided 3).")
|
||||
fail(t, so(0, ShouldBeChronological), shouldUseTimeSlice)
|
||||
fail(t, so([]time.Time{january5, january1}, ShouldBeChronological),
|
||||
"The 'Time' at index [1] should have happened after the previous one (but it didn't!):\n [0]: 2013-01-05 00:00:00 +0000 UTC\n [1]: 2013-01-01 00:00:00 +0000 UTC (see, it happened before!)")
|
||||
|
||||
pass(t, so([]time.Time{january1, january2, january3, january4, january5}, ShouldBeChronological))
|
||||
}
|
||||
|
||||
const layout = "2006-01-02 15:04"
|
||||
|
||||
var january1, _ = time.Parse(layout, "2013-01-01 00:00")
|
||||
var january2, _ = time.Parse(layout, "2013-01-02 00:00")
|
||||
var january3, _ = time.Parse(layout, "2013-01-03 00:00")
|
||||
var january4, _ = time.Parse(layout, "2013-01-04 00:00")
|
||||
var january5, _ = time.Parse(layout, "2013-01-05 00:00")
|
||||
|
||||
var oneDay, _ = time.ParseDuration("24h0m0s")
|
||||
var twoDays, _ = time.ParseDuration("48h0m0s")
|
||||
|
||||
func pretty(t time.Time) string {
|
||||
return fmt.Sprintf("%v", t)
|
||||
}
|
112
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type.go
generated
vendored
112
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type.go
generated
vendored
@ -1,112 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// ShouldHaveSameTypeAs receives exactly two parameters and compares their underlying types for equality.
|
||||
func ShouldHaveSameTypeAs(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
first := reflect.TypeOf(actual)
|
||||
second := reflect.TypeOf(expected[0])
|
||||
|
||||
if equal := ShouldEqual(first, second); equal != success {
|
||||
return serializer.serialize(second, first, fmt.Sprintf(shouldHaveBeenA, actual, second, first))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotHaveSameTypeAs receives exactly two parameters and compares their underlying types for inequality.
|
||||
func ShouldNotHaveSameTypeAs(actual interface{}, expected ...interface{}) string {
|
||||
if fail := need(1, expected); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
first := reflect.TypeOf(actual)
|
||||
second := reflect.TypeOf(expected[0])
|
||||
|
||||
if equal := ShouldEqual(first, second); equal == success {
|
||||
return fmt.Sprintf(shouldNotHaveBeenA, actual, second)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldImplement receives exactly two parameters and ensures
|
||||
// that the first implements the interface type of the second.
|
||||
func ShouldImplement(actual interface{}, expectedList ...interface{}) string {
|
||||
if fail := need(1, expectedList); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
expected := expectedList[0]
|
||||
if fail := ShouldBeNil(expected); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
if fail := ShouldNotBeNil(actual); fail != success {
|
||||
return shouldNotBeNilActual
|
||||
}
|
||||
|
||||
var actualType reflect.Type
|
||||
if reflect.TypeOf(actual).Kind() != reflect.Ptr {
|
||||
actualType = reflect.PtrTo(reflect.TypeOf(actual))
|
||||
} else {
|
||||
actualType = reflect.TypeOf(actual)
|
||||
}
|
||||
|
||||
expectedType := reflect.TypeOf(expected)
|
||||
if fail := ShouldNotBeNil(expectedType); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
expectedInterface := expectedType.Elem()
|
||||
|
||||
if actualType == nil {
|
||||
return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actual)
|
||||
}
|
||||
|
||||
if !actualType.Implements(expectedInterface) {
|
||||
return fmt.Sprintf(shouldHaveImplemented, expectedInterface, actualType)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// ShouldNotImplement receives exactly two parameters and ensures
|
||||
// that the first does NOT implement the interface type of the second.
|
||||
func ShouldNotImplement(actual interface{}, expectedList ...interface{}) string {
|
||||
if fail := need(1, expectedList); fail != success {
|
||||
return fail
|
||||
}
|
||||
|
||||
expected := expectedList[0]
|
||||
if fail := ShouldBeNil(expected); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
if fail := ShouldNotBeNil(actual); fail != success {
|
||||
return shouldNotBeNilActual
|
||||
}
|
||||
|
||||
var actualType reflect.Type
|
||||
if reflect.TypeOf(actual).Kind() != reflect.Ptr {
|
||||
actualType = reflect.PtrTo(reflect.TypeOf(actual))
|
||||
} else {
|
||||
actualType = reflect.TypeOf(actual)
|
||||
}
|
||||
|
||||
expectedType := reflect.TypeOf(expected)
|
||||
if fail := ShouldNotBeNil(expectedType); fail != success {
|
||||
return shouldCompareWithInterfacePointer
|
||||
}
|
||||
|
||||
expectedInterface := expectedType.Elem()
|
||||
|
||||
if actualType.Implements(expectedInterface) {
|
||||
return fmt.Sprintf(shouldNotHaveImplemented, actualType, expectedInterface)
|
||||
}
|
||||
return success
|
||||
}
|
76
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type_test.go
generated
vendored
76
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/assertions/type_test.go
generated
vendored
@ -1,76 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShouldHaveSameTypeAs(t *testing.T) {
|
||||
serializer = newFakeSerializer()
|
||||
|
||||
fail(t, so(1, ShouldHaveSameTypeAs), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldHaveSameTypeAs, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(nil, ShouldHaveSameTypeAs, 0), "int|<nil>|Expected '<nil>' to be: 'int' (but was: '<nil>')!")
|
||||
fail(t, so(1, ShouldHaveSameTypeAs, "asdf"), "string|int|Expected '1' to be: 'string' (but was: 'int')!")
|
||||
|
||||
pass(t, so(1, ShouldHaveSameTypeAs, 0))
|
||||
pass(t, so(nil, ShouldHaveSameTypeAs, nil))
|
||||
}
|
||||
|
||||
func TestShouldNotHaveSameTypeAs(t *testing.T) {
|
||||
fail(t, so(1, ShouldNotHaveSameTypeAs), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(1, ShouldNotHaveSameTypeAs, 1, 2, 3), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(1, ShouldNotHaveSameTypeAs, 0), "Expected '1' to NOT be: 'int' (but it was)!")
|
||||
fail(t, so(nil, ShouldNotHaveSameTypeAs, nil), "Expected '<nil>' to NOT be: '<nil>' (but it was)!")
|
||||
|
||||
pass(t, so(nil, ShouldNotHaveSameTypeAs, 0))
|
||||
pass(t, so(1, ShouldNotHaveSameTypeAs, "asdf"))
|
||||
}
|
||||
|
||||
func TestShouldImplement(t *testing.T) {
|
||||
var ioReader *io.Reader = nil
|
||||
var response http.Response = http.Response{}
|
||||
var responsePtr *http.Response = new(http.Response)
|
||||
var reader = bytes.NewBufferString("")
|
||||
|
||||
fail(t, so(reader, ShouldImplement), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(reader, ShouldImplement, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
fail(t, so(reader, ShouldImplement, ioReader, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(reader, ShouldImplement, "foo"), shouldCompareWithInterfacePointer)
|
||||
fail(t, so(reader, ShouldImplement, 1), shouldCompareWithInterfacePointer)
|
||||
fail(t, so(reader, ShouldImplement, nil), shouldCompareWithInterfacePointer)
|
||||
|
||||
fail(t, so(nil, ShouldImplement, ioReader), shouldNotBeNilActual)
|
||||
fail(t, so(1, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*int' does not implement the interface!")
|
||||
|
||||
fail(t, so(response, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*http.Response' does not implement the interface!")
|
||||
fail(t, so(responsePtr, ShouldImplement, ioReader), "Expected: 'io.Reader interface support'\nActual: '*http.Response' does not implement the interface!")
|
||||
pass(t, so(reader, ShouldImplement, ioReader))
|
||||
pass(t, so(reader, ShouldImplement, (*io.Reader)(nil)))
|
||||
}
|
||||
|
||||
func TestShouldNotImplement(t *testing.T) {
|
||||
var ioReader *io.Reader = nil
|
||||
var response http.Response = http.Response{}
|
||||
var responsePtr *http.Response = new(http.Response)
|
||||
var reader io.Reader = bytes.NewBufferString("")
|
||||
|
||||
fail(t, so(reader, ShouldNotImplement), "This assertion requires exactly 1 comparison values (you provided 0).")
|
||||
fail(t, so(reader, ShouldNotImplement, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 2).")
|
||||
fail(t, so(reader, ShouldNotImplement, ioReader, ioReader, ioReader), "This assertion requires exactly 1 comparison values (you provided 3).")
|
||||
|
||||
fail(t, so(reader, ShouldNotImplement, "foo"), shouldCompareWithInterfacePointer)
|
||||
fail(t, so(reader, ShouldNotImplement, 1), shouldCompareWithInterfacePointer)
|
||||
fail(t, so(reader, ShouldNotImplement, nil), shouldCompareWithInterfacePointer)
|
||||
|
||||
fail(t, so(reader, ShouldNotImplement, ioReader), "Expected '*bytes.Buffer'\nto NOT implement 'io.Reader' (but it did)!")
|
||||
fail(t, so(nil, ShouldNotImplement, ioReader), shouldNotBeNilActual)
|
||||
pass(t, so(1, ShouldNotImplement, ioReader))
|
||||
pass(t, so(response, ShouldNotImplement, ioReader))
|
||||
pass(t, so(responsePtr, ShouldNotImplement, ioReader))
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
package assertions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func pass(t *testing.T, result string) {
|
||||
if result != success {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
base := path.Base(file)
|
||||
t.Errorf("Expectation should have passed but failed (see %s: line %d): '%s'", base, line, result)
|
||||
}
|
||||
}
|
||||
|
||||
func fail(t *testing.T, actual string, expected string) {
|
||||
actual = format(actual)
|
||||
expected = format(expected)
|
||||
|
||||
if actual != expected {
|
||||
if actual == "" {
|
||||
actual = "(empty)"
|
||||
}
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
base := path.Base(file)
|
||||
t.Errorf("Expectation should have failed but passed (see %s: line %d). \nExpected: %s\nActual: %s\n",
|
||||
base, line, expected, actual)
|
||||
}
|
||||
}
|
||||
func format(message string) string {
|
||||
message = strings.Replace(message, "\n", " ", -1)
|
||||
for strings.Contains(message, " ") {
|
||||
message = strings.Replace(message, " ", " ", -1)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
func so(actual interface{}, assert func(interface{}, ...interface{}) string, expected ...interface{}) string {
|
||||
return assert(actual, expected...)
|
||||
}
|
||||
|
||||
type Thing1 struct {
|
||||
a string
|
||||
}
|
||||
type Thing2 struct {
|
||||
a string
|
||||
}
|
||||
|
||||
type Thinger interface {
|
||||
Hi()
|
||||
}
|
||||
|
||||
type Thing struct{}
|
||||
|
||||
func (self *Thing) Hi() {}
|
||||
|
||||
type IntAlias int
|
||||
type StringAlias string
|
||||
type StringSliceAlias []string
|
||||
type StringStringMapAlias map[string]string
|
||||
|
||||
/******** FakeSerialzier ********/
|
||||
|
||||
type fakeSerializer struct{}
|
||||
|
||||
func (self *fakeSerializer) serialize(expected, actual interface{}, message string) string {
|
||||
return fmt.Sprintf("%v|%v|%s", expected, actual, message)
|
||||
}
|
||||
|
||||
func newFakeSerializer() *fakeSerializer {
|
||||
return new(fakeSerializer)
|
||||
}
|
179
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/context.go
generated
vendored
179
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/context.go
generated
vendored
@ -1,179 +0,0 @@
|
||||
// Oh the stack trace scanning!
|
||||
// The density of comments in this file is evidence that
|
||||
// the code doesn't exactly explain itself. Tread with care...
|
||||
package convey
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
missingGoTest string = `Top-level calls to Convey(...) need a reference to the *testing.T.
|
||||
Hint: Convey("description here", t, func() { /* notice that the second argument was the *testing.T (t)! */ }) `
|
||||
extraGoTest string = `Only the top-level call to Convey(...) needs a reference to the *testing.T.`
|
||||
)
|
||||
|
||||
// suiteContext magically handles all coordination of reporter, runners as they handle calls
|
||||
// to Convey, So, and the like. It does this via runtime call stack inspection, making sure
|
||||
// that each test function has its own runner, and routes all live registrations
|
||||
// to the appropriate runner.
|
||||
type suiteContext struct {
|
||||
lock sync.Mutex
|
||||
runners map[string]*runner // key: testName;
|
||||
|
||||
// stores a correlation to the actual runner for outside-of-stack scenaios
|
||||
locations map[string]string // key: file:line; value: testName (key to runners)
|
||||
}
|
||||
|
||||
func (self *suiteContext) Run(entry *registration) {
|
||||
if self.current() != nil {
|
||||
panic(extraGoTest)
|
||||
}
|
||||
|
||||
runner := newRunner(buildReporter())
|
||||
|
||||
testName, location, _ := suiteAnchor()
|
||||
|
||||
self.setRunner(location, testName, runner)
|
||||
|
||||
runner.Run(entry)
|
||||
|
||||
self.unsetRunner(location, testName)
|
||||
}
|
||||
|
||||
func (self *suiteContext) Current() *runner {
|
||||
if runner := self.current(); runner != nil {
|
||||
return runner
|
||||
}
|
||||
panic(missingGoTest)
|
||||
}
|
||||
func (self *suiteContext) current() *runner {
|
||||
self.lock.Lock()
|
||||
defer self.lock.Unlock()
|
||||
|
||||
if testName, _, err := suiteAnchor(); err == nil {
|
||||
return self.runners[testName]
|
||||
}
|
||||
|
||||
return self.runners[correlate(self.locations)]
|
||||
}
|
||||
func (self *suiteContext) setRunner(location string, testName string, runner *runner) {
|
||||
self.lock.Lock()
|
||||
defer self.lock.Unlock()
|
||||
|
||||
self.locations[location] = testName
|
||||
self.runners[testName] = runner
|
||||
}
|
||||
func (self *suiteContext) unsetRunner(location string, testName string) {
|
||||
self.lock.Lock()
|
||||
defer self.lock.Unlock()
|
||||
|
||||
delete(self.locations, location)
|
||||
delete(self.runners, testName)
|
||||
}
|
||||
|
||||
func newSuiteContext() *suiteContext {
|
||||
return &suiteContext{
|
||||
locations: map[string]string{},
|
||||
runners: map[string]*runner{},
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////// Helper Functions ///////////////////////
|
||||
|
||||
// suiteAnchor returns the enclosing test function name (including package) and the
|
||||
// file:line combination of the top-level Convey. It does this by traversing the
|
||||
// call stack in reverse, looking for the go testing harnass call ("testing.tRunner")
|
||||
// and then grabs the very next entry.
|
||||
func suiteAnchor() (testName, location string, err error) {
|
||||
callers := runtime.Callers(0, callStack)
|
||||
|
||||
for y := callers; y > 0; y-- {
|
||||
callerId, file, conveyLine, found := runtime.Caller(y)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
if name := runtime.FuncForPC(callerId).Name(); name != goTestHarness {
|
||||
continue
|
||||
}
|
||||
|
||||
callerId, file, conveyLine, _ = runtime.Caller(y - 1)
|
||||
testName = runtime.FuncForPC(callerId).Name()
|
||||
location = fmt.Sprintf("%s:%d", file, conveyLine)
|
||||
return
|
||||
}
|
||||
return "", "", errors.New("Can't resolve test method name! Are you calling Convey() from a `*_test.go` file and a `Test*` method (because you should be)?")
|
||||
}
|
||||
|
||||
// correlate links the current stack with the appropriate
|
||||
// top-level Convey by comparing line numbers in its own stack trace
|
||||
// with the registered file:line combo. It's come to this.
|
||||
func correlate(locations map[string]string) (testName string) {
|
||||
file, line := resolveTestFileAndLine()
|
||||
closest := -1
|
||||
|
||||
for location, registeredTestName := range locations {
|
||||
locationFile, rawLocationLine := splitFileAndLine(location)
|
||||
|
||||
if locationFile != file {
|
||||
continue
|
||||
}
|
||||
|
||||
locationLine, err := strconv.Atoi(rawLocationLine)
|
||||
if err != nil || locationLine < line {
|
||||
continue
|
||||
}
|
||||
|
||||
if closest == -1 || locationLine < closest {
|
||||
closest = locationLine
|
||||
testName = registeredTestName
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// splitFileAndLine receives a path and a line number in a single string,
|
||||
// separated by a colon and splits them.
|
||||
func splitFileAndLine(value string) (file, line string) {
|
||||
parts := strings.Split(value, ":")
|
||||
if len(parts) == 2 {
|
||||
file = parts[0]
|
||||
line = parts[1]
|
||||
} else if len(parts) > 2 {
|
||||
// 'C:/blah.go:123' (windows drive letter has two colons
|
||||
// '-:--------:---' instead of just one to separate file and line)
|
||||
file = strings.Join(parts[:2], ":")
|
||||
line = parts[2]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// resolveTestFileAndLine is used as a last-ditch effort to correlate an
|
||||
// assertion with the right executor and runner.
|
||||
func resolveTestFileAndLine() (file string, line int) {
|
||||
callers := runtime.Callers(0, callStack)
|
||||
var found bool
|
||||
|
||||
for y := callers; y > 0; y-- {
|
||||
_, file, line, found = runtime.Caller(y)
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasSuffix(file, "_test.go") {
|
||||
return
|
||||
}
|
||||
}
|
||||
return "", 0
|
||||
}
|
||||
|
||||
const maxStackDepth = 100 // This had better be enough...
|
||||
const goTestHarness = "testing.tRunner" // I hope this doesn't change...
|
||||
|
||||
var callStack []uintptr = make([]uintptr, maxStackDepth, maxStackDepth)
|
57
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/discovery.go
generated
vendored
57
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/discovery.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package convey
|
||||
|
||||
func discover(items []interface{}) *registration {
|
||||
name, items := parseName(items)
|
||||
test, items := parseGoTest(items)
|
||||
action, items := parseAction(items)
|
||||
|
||||
if len(items) != 0 {
|
||||
panic(parseError)
|
||||
}
|
||||
|
||||
return newRegistration(name, action, test)
|
||||
}
|
||||
func item(items []interface{}) interface{} {
|
||||
if len(items) == 0 {
|
||||
panic(parseError)
|
||||
}
|
||||
return items[0]
|
||||
}
|
||||
func parseName(items []interface{}) (string, []interface{}) {
|
||||
if name, parsed := item(items).(string); parsed {
|
||||
return name, items[1:]
|
||||
}
|
||||
panic(parseError)
|
||||
}
|
||||
func parseGoTest(items []interface{}) (t, []interface{}) {
|
||||
if test, parsed := item(items).(t); parsed {
|
||||
return test, items[1:]
|
||||
}
|
||||
return nil, items
|
||||
}
|
||||
func parseFailureMode(items []interface{}) (FailureMode, []interface{}) {
|
||||
if mode, parsed := item(items).(FailureMode); parsed {
|
||||
return mode, items[1:]
|
||||
}
|
||||
return FailureInherits, items
|
||||
}
|
||||
func parseAction(items []interface{}) (*action, []interface{}) {
|
||||
failure, items := parseFailureMode(items)
|
||||
|
||||
if action, parsed := item(items).(func()); parsed {
|
||||
return newAction(action, failure), items[1:]
|
||||
}
|
||||
if item(items) == nil {
|
||||
return newSkippedAction(skipReport, failure), items[1:]
|
||||
}
|
||||
panic(parseError)
|
||||
}
|
||||
|
||||
// This interface allows us to pass the *testing.T struct
|
||||
// throughout the internals of this tool without ever
|
||||
// having to import the "testing" package.
|
||||
type t interface {
|
||||
Fail()
|
||||
}
|
||||
|
||||
const parseError = "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode, and then an action (func())."
|
178
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/doc.go
generated
vendored
178
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/doc.go
generated
vendored
@ -1,178 +0,0 @@
|
||||
// Package convey contains all of the public-facing entry points to this project.
|
||||
// This means that it should never be required of the user to import any other
|
||||
// packages from this project as they serve internal purposes.
|
||||
package convey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
////////////////////////////////// Registration //////////////////////////////////
|
||||
|
||||
// Convey is the method intended for use when declaring the scopes
|
||||
// of a specification. Each scope has a description and a func()
|
||||
// which may contain other calls to Convey(), Reset() or Should-style
|
||||
// assertions. Convey calls can be nested as far as you see fit.
|
||||
//
|
||||
// IMPORTANT NOTE: The top-level Convey() within a Test method
|
||||
// must conform to the following signature:
|
||||
//
|
||||
// Convey(description string, t *testing.T, action func())
|
||||
//
|
||||
// All other calls should like like this (no need to pass in *testing.T):
|
||||
//
|
||||
// Convey(description string, action func())
|
||||
//
|
||||
// Don't worry, the goconvey will panic if you get it wrong so you can fix it.
|
||||
//
|
||||
// All Convey()-blocks also take an optional parameter of FailureMode which
|
||||
// sets how goconvey should treat failures for So()-assertions in the block and
|
||||
// nested blocks. See the constants in this file for the available options.
|
||||
//
|
||||
// By default it will inherit from its parent block and the top-level blocks
|
||||
// start with setting of FailureHalts.
|
||||
//
|
||||
// This parameter is inserted before the block itself:
|
||||
//
|
||||
// Convey(description string, t *testing.T, mode FailureMode, action func())
|
||||
// Convey(description string, mode FailureMode, action func())
|
||||
//
|
||||
// See the examples package for, well, examples.
|
||||
func Convey(items ...interface{}) {
|
||||
register(discover(items))
|
||||
}
|
||||
|
||||
// SkipConvey is analagous to Convey except that the scope is not executed
|
||||
// (which means that child scopes defined within this scope are not run either).
|
||||
// The reporter will be notified that this step was skipped.
|
||||
func SkipConvey(items ...interface{}) {
|
||||
entry := discover(items)
|
||||
entry.action = newSkippedAction(skipReport, entry.action.failureMode)
|
||||
|
||||
register(entry)
|
||||
}
|
||||
|
||||
// FocusConvey is has the inverse effect of SkipConvey. If the top-level
|
||||
// Convey is changed to `FocusConvey`, only nested scopes that are defined
|
||||
// with FocusConvey will be run. The rest will be ignored completely. This
|
||||
// is handy when debugging a large suite that runs a misbehaving function
|
||||
// repeatedly as you can disable all but one of that function
|
||||
// without swaths of `SkipConvey` calls, just a targeted chain of calls
|
||||
// to FocusConvey.
|
||||
func FocusConvey(items ...interface{}) {
|
||||
entry := discover(items)
|
||||
entry.Focus = true
|
||||
|
||||
register(entry)
|
||||
}
|
||||
|
||||
func register(entry *registration) {
|
||||
if entry.ShouldBeTopLevel() {
|
||||
suites.Run(entry)
|
||||
} else {
|
||||
suites.Current().Register(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func skipReport() {
|
||||
suites.Current().Report(reporting.NewSkipReport())
|
||||
}
|
||||
|
||||
// Reset registers a cleanup function to be run after each Convey()
|
||||
// in the same scope. See the examples package for a simple use case.
|
||||
func Reset(action func()) {
|
||||
/* TODO: Failure mode configuration */
|
||||
suites.Current().RegisterReset(newAction(action, FailureInherits))
|
||||
}
|
||||
|
||||
/////////////////////////////////// Assertions ///////////////////////////////////
|
||||
|
||||
// assertion is an alias for a function with a signature that the convey.So()
|
||||
// method can handle. Any future or custom assertions should conform to this
|
||||
// method signature. The return value should be an empty string if the assertion
|
||||
// passes and a well-formed failure message if not.
|
||||
type assertion func(actual interface{}, expected ...interface{}) string
|
||||
|
||||
const assertionSuccess = ""
|
||||
|
||||
// So is the means by which assertions are made against the system under test.
|
||||
// The majority of exported names in the assertions package begin with the word
|
||||
// 'Should' and describe how the first argument (actual) should compare with any
|
||||
// of the final (expected) arguments. How many final arguments are accepted
|
||||
// depends on the particular assertion that is passed in as the assert argument.
|
||||
// See the examples package for use cases and the assertions package for
|
||||
// documentation on specific assertion methods.
|
||||
func So(actual interface{}, assert assertion, expected ...interface{}) {
|
||||
if result := assert(actual, expected...); result == assertionSuccess {
|
||||
suites.Current().Report(reporting.NewSuccessReport())
|
||||
} else {
|
||||
suites.Current().Report(reporting.NewFailureReport(result))
|
||||
}
|
||||
}
|
||||
|
||||
// SkipSo is analagous to So except that the assertion that would have been passed
|
||||
// to So is not executed and the reporter is notified that the assertion was skipped.
|
||||
func SkipSo(stuff ...interface{}) {
|
||||
skipReport()
|
||||
}
|
||||
|
||||
// FailureMode is a type which determines how the So() blocks should fail
|
||||
// if their assertion fails. See constants further down for acceptable values
|
||||
type FailureMode string
|
||||
|
||||
const (
|
||||
|
||||
// FailureContinues is a failure mode which prevents failing
|
||||
// So()-assertions from halting Convey-block execution, instead
|
||||
// allowing the test to continue past failing So()-assertions.
|
||||
FailureContinues FailureMode = "continue"
|
||||
|
||||
// FailureHalts is the default setting for a top-level Convey()-block
|
||||
// and will cause all failing So()-assertions to halt further execution
|
||||
// in that test-arm and continue on to the next arm.
|
||||
FailureHalts FailureMode = "halt"
|
||||
|
||||
// FailureInherits is the default setting for failure-mode, it will
|
||||
// default to the failure-mode of the parent block. You should never
|
||||
// need to specify this mode in your tests..
|
||||
FailureInherits FailureMode = "inherits"
|
||||
)
|
||||
|
||||
var defaultFailureMode FailureMode = FailureHalts
|
||||
|
||||
// SetDefaultFailureMode allows you to specify the default failure mode
|
||||
// for all Convey blocks. It is meant to be used in an init function to
|
||||
// allow the default mode to be changd across all tests for an entire packgae
|
||||
// but it can be used anywhere.
|
||||
func SetDefaultFailureMode(mode FailureMode) {
|
||||
if mode == FailureContinues || mode == FailureHalts {
|
||||
defaultFailureMode = mode
|
||||
} else {
|
||||
panic("You may only use the constants named 'FailureContinues' and 'FailureHalts' as default failure modes.")
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////// Print functions ////////////////////////////////////
|
||||
|
||||
// Print is analogous to fmt.Print (and it even calls fmt.Print). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Print(items ...interface{}) (written int, err error) {
|
||||
fmt.Fprint(suites.Current(), items...)
|
||||
return fmt.Print(items...)
|
||||
}
|
||||
|
||||
// Print is analogous to fmt.Println (and it even calls fmt.Println). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Println(items ...interface{}) (written int, err error) {
|
||||
fmt.Fprintln(suites.Current(), items...)
|
||||
return fmt.Println(items...)
|
||||
}
|
||||
|
||||
// Print is analogous to fmt.Printf (and it even calls fmt.Printf). It ensures that
|
||||
// output is aligned with the corresponding scopes in the web UI.
|
||||
func Printf(format string, items ...interface{}) (written int, err error) {
|
||||
fmt.Fprintf(suites.Current(), format, items...)
|
||||
return fmt.Printf(format, items...)
|
||||
}
|
72
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/focused_execution_test.go
generated
vendored
72
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/focused_execution_test.go
generated
vendored
@ -1,72 +0,0 @@
|
||||
package convey
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFocusOnlyAtTopLevel(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
FocusConvey("hi", t, func() {
|
||||
output += "done"
|
||||
})
|
||||
|
||||
expectEqual(t, "done", output)
|
||||
}
|
||||
|
||||
func TestFocus(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
FocusConvey("hi", t, func() {
|
||||
output += "1"
|
||||
|
||||
Convey("bye", func() {
|
||||
output += "2"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "1", output)
|
||||
}
|
||||
|
||||
func TestNestedFocus(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
FocusConvey("hi", t, func() {
|
||||
output += "1"
|
||||
|
||||
Convey("This shouldn't run", func() {
|
||||
output += "boink!"
|
||||
})
|
||||
|
||||
FocusConvey("This should run", func() {
|
||||
output += "2"
|
||||
|
||||
FocusConvey("The should run too", func() {
|
||||
output += "3"
|
||||
|
||||
})
|
||||
|
||||
Convey("The should NOT run", func() {
|
||||
output += "blah blah blah!"
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "123", output)
|
||||
}
|
||||
|
||||
func TestForgotTopLevelFocus(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("1", t, func() {
|
||||
output += "1"
|
||||
|
||||
FocusConvey("This will be run because the top-level lacks Focus", func() {
|
||||
output += "2"
|
||||
})
|
||||
|
||||
Convey("3", func() {
|
||||
output += "3"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "1213", output)
|
||||
}
|
37
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/gotest/utils.go
generated
vendored
37
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/gotest/utils.go
generated
vendored
@ -1,37 +0,0 @@
|
||||
// Package gotest contains internal functionality. Although this package
|
||||
// contains one or more exported names it is not intended for public
|
||||
// consumption. See the examples package for how to use this project.
|
||||
package gotest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func FormatExternalFileAndLine() string {
|
||||
file, line, _ := ResolveExternalCaller()
|
||||
if line == -1 {
|
||||
return "<unknown caller!>" // panic?
|
||||
}
|
||||
return fmt.Sprintf("%s:%d", file, line)
|
||||
}
|
||||
|
||||
func ResolveExternalCaller() (file string, line int, name string) {
|
||||
var caller_id uintptr
|
||||
callers := runtime.Callers(0, callStack)
|
||||
|
||||
for x := 0; x < callers; x++ {
|
||||
caller_id, file, line, _ = runtime.Caller(x)
|
||||
if strings.HasSuffix(file, "_test.go") {
|
||||
name = runtime.FuncForPC(caller_id).Name()
|
||||
return
|
||||
}
|
||||
}
|
||||
file, line, name = "<unkown file>", -1, "<unknown name>"
|
||||
return // panic?
|
||||
}
|
||||
|
||||
const maxStackDepth = 100 // This had better be enough...
|
||||
|
||||
var callStack []uintptr = make([]uintptr, maxStackDepth, maxStackDepth)
|
72
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/init.go
generated
vendored
72
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/init.go
generated
vendored
@ -1,72 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
func init() {
|
||||
declareFlags()
|
||||
|
||||
suites = newSuiteContext()
|
||||
}
|
||||
|
||||
func declareFlags() {
|
||||
flag.BoolVar(&json, "json", false, "When true, emits results in JSON blocks. Default: 'false'")
|
||||
flag.BoolVar(&silent, "silent", false, "When true, all output from GoConvey is suppressed.")
|
||||
flag.BoolVar(&story, "story", false, "When true, emits story output, otherwise emits dot output. When not provided, this flag mirros the value of the '-test.v' flag")
|
||||
|
||||
if noStoryFlagProvided() {
|
||||
story = verboseEnabled
|
||||
}
|
||||
|
||||
// FYI: flag.Parse() is called from the testing package.
|
||||
}
|
||||
|
||||
func noStoryFlagProvided() bool {
|
||||
return !story && !storyDisabled
|
||||
}
|
||||
|
||||
func buildReporter() reporting.Reporter {
|
||||
switch {
|
||||
case testReporter != nil:
|
||||
return testReporter
|
||||
case json:
|
||||
return reporting.BuildJsonReporter()
|
||||
case silent:
|
||||
return reporting.BuildSilentReporter()
|
||||
case story:
|
||||
return reporting.BuildStoryReporter()
|
||||
default:
|
||||
return reporting.BuildDotReporter()
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
suites *suiteContext
|
||||
|
||||
// only set by internal tests
|
||||
testReporter reporting.Reporter
|
||||
)
|
||||
|
||||
var (
|
||||
json bool
|
||||
silent bool
|
||||
story bool
|
||||
|
||||
verboseEnabled = flagFound("-test.v=true")
|
||||
storyDisabled = flagFound("-story=false")
|
||||
)
|
||||
|
||||
// flagFound parses the command line args manually for flags defined in other
|
||||
// packages. Like the '-v' flag from the "testing" package, for instance.
|
||||
func flagFound(flagValue string) bool {
|
||||
for _, arg := range os.Args {
|
||||
if arg == flagValue {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
742
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/isolated_execution_test.go
generated
vendored
742
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/isolated_execution_test.go
generated
vendored
@ -1,742 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSingleScope(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("hi", t, func() {
|
||||
output += "done"
|
||||
})
|
||||
|
||||
expectEqual(t, "done", output)
|
||||
}
|
||||
|
||||
func TestSingleScopeWithMultipleConveys(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("1", t, func() {
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("2", t, func() {
|
||||
output += "2"
|
||||
})
|
||||
|
||||
expectEqual(t, "12", output)
|
||||
}
|
||||
|
||||
func TestNestedScopes(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("a", t, func() {
|
||||
output += "a "
|
||||
|
||||
Convey("bb", func() {
|
||||
output += "bb "
|
||||
|
||||
Convey("ccc", func() {
|
||||
output += "ccc | "
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "a bb ccc | ", output)
|
||||
}
|
||||
|
||||
func TestNestedScopesWithIsolatedExecution(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("a", t, func() {
|
||||
output += "a "
|
||||
|
||||
Convey("aa", func() {
|
||||
output += "aa "
|
||||
|
||||
Convey("aaa", func() {
|
||||
output += "aaa | "
|
||||
})
|
||||
|
||||
Convey("aaa1", func() {
|
||||
output += "aaa1 | "
|
||||
})
|
||||
})
|
||||
|
||||
Convey("ab", func() {
|
||||
output += "ab "
|
||||
|
||||
Convey("abb", func() {
|
||||
output += "abb | "
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "a aa aaa | a aa aaa1 | a ab abb | ", output)
|
||||
}
|
||||
|
||||
func TestSingleScopeWithConveyAndNestedReset(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("1", t, func() {
|
||||
output += "1"
|
||||
|
||||
Reset(func() {
|
||||
output += "a"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "1a", output)
|
||||
}
|
||||
|
||||
func TestSingleScopeWithMultipleRegistrationsAndReset(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("reset after each nested convey", t, func() {
|
||||
Convey("first output", func() {
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("second output", func() {
|
||||
output += "2"
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
output += "a"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "1a2a", output)
|
||||
}
|
||||
|
||||
func TestSingleScopeWithMultipleRegistrationsAndMultipleResets(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("each reset is run at end of each nested convey", t, func() {
|
||||
Convey("1", func() {
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("2", func() {
|
||||
output += "2"
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
output += "a"
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
output += "b"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "1ab2ab", output)
|
||||
}
|
||||
|
||||
func Test_Failure_AtHigherLevelScopePreventsChildScopesFromRunning(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This step fails", t, func() {
|
||||
So(1, ShouldEqual, 2)
|
||||
|
||||
Convey("this should NOT be executed", func() {
|
||||
output += "a"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "", output)
|
||||
}
|
||||
|
||||
func Test_Panic_AtHigherLevelScopePreventsChildScopesFromRunning(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This step panics", t, func() {
|
||||
Convey("this should NOT be executed", func() {
|
||||
output += "1"
|
||||
})
|
||||
|
||||
panic("Hi")
|
||||
})
|
||||
|
||||
expectEqual(t, "", output)
|
||||
}
|
||||
|
||||
func Test_Panic_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This is the parent", t, func() {
|
||||
Convey("This step panics", func() {
|
||||
panic("Hi")
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("This sibling should execute", func() {
|
||||
output += "2"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "2", output)
|
||||
}
|
||||
|
||||
func Test_Failure_InChildScopeDoes_NOT_PreventExecutionOfSiblingScopes(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This is the parent", t, func() {
|
||||
Convey("This step fails", func() {
|
||||
So(1, ShouldEqual, 2)
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("This sibling should execute", func() {
|
||||
output += "2"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "2", output)
|
||||
}
|
||||
|
||||
func TestResetsAreAlwaysExecutedAfterScope_Panics(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This is the parent", t, func() {
|
||||
Convey("This step panics", func() {
|
||||
panic("Hi")
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("This sibling step does not panic", func() {
|
||||
output += "a"
|
||||
|
||||
Reset(func() {
|
||||
output += "b"
|
||||
})
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
output += "2"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "2ab2", output)
|
||||
}
|
||||
|
||||
func TestResetsAreAlwaysExecutedAfterScope_Failures(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("This is the parent", t, func() {
|
||||
Convey("This step fails", func() {
|
||||
So(1, ShouldEqual, 2)
|
||||
output += "1"
|
||||
})
|
||||
|
||||
Convey("This sibling step does not fail", func() {
|
||||
output += "a"
|
||||
|
||||
Reset(func() {
|
||||
output += "b"
|
||||
})
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
output += "2"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "2ab2", output)
|
||||
}
|
||||
|
||||
func TestSkipTopLevel(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
SkipConvey("hi", t, func() {
|
||||
output += "This shouldn't be executed!"
|
||||
})
|
||||
|
||||
expectEqual(t, "", output)
|
||||
}
|
||||
|
||||
func TestSkipNestedLevel(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("hi", t, func() {
|
||||
output += "yes"
|
||||
|
||||
SkipConvey("bye", func() {
|
||||
output += "no"
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "yes", output)
|
||||
}
|
||||
|
||||
func TestSkipNestedLevelSkipsAllChildLevels(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("hi", t, func() {
|
||||
output += "yes"
|
||||
|
||||
SkipConvey("bye", func() {
|
||||
output += "no"
|
||||
|
||||
Convey("byebye", func() {
|
||||
output += "no-no"
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "yes", output)
|
||||
}
|
||||
|
||||
func TestIterativeConveys(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("Test", t, func() {
|
||||
for x := 0; x < 10; x++ {
|
||||
y := strconv.Itoa(x)
|
||||
|
||||
Convey(y, func() {
|
||||
output += y
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
expectEqual(t, "0123456789", output)
|
||||
}
|
||||
|
||||
func TestClosureVariables(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
i := 0
|
||||
|
||||
Convey("A", t, func() {
|
||||
i = i + 1
|
||||
j := i
|
||||
|
||||
output += "A" + strconv.Itoa(i) + " "
|
||||
|
||||
Convey("B", func() {
|
||||
k := j
|
||||
j = j + 1
|
||||
|
||||
output += "B" + strconv.Itoa(k) + " "
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C" + strconv.Itoa(k) + strconv.Itoa(j) + " "
|
||||
})
|
||||
|
||||
Convey("D", func() {
|
||||
output += "D" + strconv.Itoa(k) + strconv.Itoa(j) + " "
|
||||
})
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C" + strconv.Itoa(j) + " "
|
||||
})
|
||||
})
|
||||
|
||||
output += "D" + strconv.Itoa(i) + " "
|
||||
|
||||
expectEqual(t, "A1 B1 C12 A2 B2 D23 A3 C3 D3 ", output)
|
||||
}
|
||||
|
||||
func TestClosureVariablesWithReset(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
i := 0
|
||||
|
||||
Convey("A", t, func() {
|
||||
i = i + 1
|
||||
j := i
|
||||
|
||||
output += "A" + strconv.Itoa(i) + " "
|
||||
|
||||
Reset(func() {
|
||||
output += "R" + strconv.Itoa(i) + strconv.Itoa(j) + " "
|
||||
})
|
||||
|
||||
Convey("B", func() {
|
||||
output += "B" + strconv.Itoa(j) + " "
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C" + strconv.Itoa(j) + " "
|
||||
})
|
||||
})
|
||||
|
||||
output += "D" + strconv.Itoa(i) + " "
|
||||
|
||||
expectEqual(t, "A1 B1 R11 A2 C2 R22 D2 ", output)
|
||||
}
|
||||
|
||||
func TestWrappedSimple(t *testing.T) {
|
||||
prepare()
|
||||
output := resetTestString{""}
|
||||
|
||||
Convey("A", t, func() {
|
||||
func() {
|
||||
output.output += "A "
|
||||
|
||||
Convey("B", func() {
|
||||
output.output += "B "
|
||||
|
||||
Convey("C", func() {
|
||||
output.output += "C "
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Convey("D", func() {
|
||||
output.output += "D "
|
||||
})
|
||||
}()
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C A D ", output.output)
|
||||
}
|
||||
|
||||
type resetTestString struct {
|
||||
output string
|
||||
}
|
||||
|
||||
func addReset(o *resetTestString, f func()) func() {
|
||||
return func() {
|
||||
Reset(func() {
|
||||
o.output += "R "
|
||||
})
|
||||
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWrappedReset(t *testing.T) {
|
||||
prepare()
|
||||
output := resetTestString{""}
|
||||
|
||||
Convey("A", t, addReset(&output, func() {
|
||||
output.output += "A "
|
||||
|
||||
Convey("B", func() {
|
||||
output.output += "B "
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output.output += "C "
|
||||
})
|
||||
}))
|
||||
|
||||
expectEqual(t, "A B R A C R ", output.output)
|
||||
}
|
||||
|
||||
func TestWrappedReset2(t *testing.T) {
|
||||
prepare()
|
||||
output := resetTestString{""}
|
||||
|
||||
Convey("A", t, func() {
|
||||
Reset(func() {
|
||||
output.output += "R "
|
||||
})
|
||||
|
||||
func() {
|
||||
output.output += "A "
|
||||
|
||||
Convey("B", func() {
|
||||
output.output += "B "
|
||||
|
||||
Convey("C", func() {
|
||||
output.output += "C "
|
||||
})
|
||||
})
|
||||
|
||||
Convey("D", func() {
|
||||
output.output += "D "
|
||||
})
|
||||
}()
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C R A D R ", output.output)
|
||||
}
|
||||
|
||||
func TestInfiniteLoopWithTrailingFail(t *testing.T) {
|
||||
done := make(chan int)
|
||||
|
||||
go func() {
|
||||
Convey("This fails", t, func() {
|
||||
Convey("and this is run", func() {
|
||||
So(true, ShouldEqual, true)
|
||||
})
|
||||
|
||||
/* And this prevents the whole block to be marked as run */
|
||||
So(false, ShouldEqual, true)
|
||||
})
|
||||
|
||||
done <- 1
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-time.After(1 * time.Millisecond):
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutermostResetInvokedForGrandchildren(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, func() {
|
||||
output += "A "
|
||||
|
||||
Reset(func() {
|
||||
output += "rA "
|
||||
})
|
||||
|
||||
Convey("B", func() {
|
||||
output += "B "
|
||||
|
||||
Reset(func() {
|
||||
output += "rB "
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C "
|
||||
|
||||
Reset(func() {
|
||||
output += "rC "
|
||||
})
|
||||
})
|
||||
|
||||
Convey("D", func() {
|
||||
output += "D "
|
||||
|
||||
Reset(func() {
|
||||
output += "rD "
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C rC rB rA A B D rD rB rA ", output)
|
||||
}
|
||||
|
||||
func TestFailureOption(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureHalts, func() {
|
||||
output += "A "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "C "
|
||||
})
|
||||
|
||||
expectEqual(t, "A B ", output)
|
||||
}
|
||||
|
||||
func TestFailureOption2(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, func() {
|
||||
output += "A "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "C "
|
||||
})
|
||||
|
||||
expectEqual(t, "A B ", output)
|
||||
}
|
||||
|
||||
func TestFailureOption3(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureContinues, func() {
|
||||
output += "A "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "C "
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C ", output)
|
||||
}
|
||||
|
||||
func TestFailureOptionInherit(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureContinues, func() {
|
||||
output += "A1 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
|
||||
Convey("B", func() {
|
||||
output += "B1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "B3 "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 A2 B1 B2 B3 ", output)
|
||||
}
|
||||
|
||||
func TestFailureOptionInherit2(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureHalts, func() {
|
||||
output += "A1 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
|
||||
Convey("B", func() {
|
||||
output += "A1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "A3 "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 ", output)
|
||||
}
|
||||
|
||||
func TestFailureOptionInherit3(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureHalts, func() {
|
||||
output += "A1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
|
||||
Convey("B", func() {
|
||||
output += "B1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "B3 "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 A2 B1 B2 ", output)
|
||||
}
|
||||
|
||||
func TestFailureOptionNestedOverride(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureContinues, func() {
|
||||
output += "A "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "B "
|
||||
|
||||
Convey("C", FailureHalts, func() {
|
||||
output += "C "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "D "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "E "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C D ", output)
|
||||
}
|
||||
|
||||
func TestFailureOptionNestedOverride2(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureHalts, func() {
|
||||
output += "A "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B "
|
||||
|
||||
Convey("C", FailureContinues, func() {
|
||||
output += "C "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "D "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "E "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A B C D E ", output)
|
||||
}
|
||||
|
||||
func TestMultipleInvocationInheritance(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureHalts, func() {
|
||||
output += "A1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
|
||||
Convey("B", FailureContinues, func() {
|
||||
output += "B1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "B3 "
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "C2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "C3 "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 A2 B1 B2 B3 A1 A2 C1 C2 ", output)
|
||||
}
|
||||
|
||||
func TestMultipleInvocationInheritance2(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, FailureContinues, func() {
|
||||
output += "A1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "A2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "A3 "
|
||||
|
||||
Convey("B", FailureHalts, func() {
|
||||
output += "B1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "B2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "B3 "
|
||||
})
|
||||
|
||||
Convey("C", func() {
|
||||
output += "C1 "
|
||||
So(true, ShouldEqual, true)
|
||||
output += "C2 "
|
||||
So(false, ShouldEqual, true)
|
||||
output += "C3 "
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 A2 A3 B1 B2 A1 A2 A3 C1 C2 C3 ", output)
|
||||
}
|
||||
|
||||
func TestSetDefaultFailureMode(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
SetDefaultFailureMode(FailureContinues) // the default is normally FailureHalts
|
||||
defer SetDefaultFailureMode(FailureHalts)
|
||||
|
||||
Convey("A", t, func() {
|
||||
output += "A1 "
|
||||
So(true, ShouldBeFalse)
|
||||
output += "A2 "
|
||||
})
|
||||
|
||||
expectEqual(t, "A1 A2 ", output)
|
||||
}
|
||||
|
||||
func prepare() string {
|
||||
testReporter = newNilReporter()
|
||||
return ""
|
||||
}
|
74
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/registration.go
generated
vendored
74
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/registration.go
generated
vendored
@ -1,74 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/gotest"
|
||||
)
|
||||
|
||||
type registration struct {
|
||||
Situation string
|
||||
action *action
|
||||
Test t
|
||||
File string
|
||||
Line int
|
||||
Focus bool
|
||||
}
|
||||
|
||||
func (self *registration) ShouldBeTopLevel() bool {
|
||||
return self.Test != nil
|
||||
}
|
||||
|
||||
func newRegistration(situation string, action *action, test t) *registration {
|
||||
file, line, _ := gotest.ResolveExternalCaller()
|
||||
|
||||
return ®istration{
|
||||
Situation: situation,
|
||||
action: action,
|
||||
Test: test,
|
||||
File: file,
|
||||
Line: line,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////// action ///////////////////////
|
||||
|
||||
type action struct {
|
||||
wrapped func()
|
||||
name string
|
||||
failureMode FailureMode
|
||||
}
|
||||
|
||||
func (self *action) Invoke() {
|
||||
self.wrapped()
|
||||
}
|
||||
|
||||
func newAction(wrapped func(), mode FailureMode) *action {
|
||||
return &action{
|
||||
name: functionName(wrapped),
|
||||
wrapped: wrapped,
|
||||
failureMode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
func newSkippedAction(wrapped func(), mode FailureMode) *action {
|
||||
// The choice to use the filename and line number as the action name
|
||||
// reflects the need for something unique but also that corresponds
|
||||
// in a determinist way to the action itself.
|
||||
return &action{
|
||||
name: gotest.FormatExternalFileAndLine(),
|
||||
wrapped: wrapped,
|
||||
failureMode: mode,
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////// helpers //////////////////////////////
|
||||
|
||||
func functionName(action func()) string {
|
||||
return runtime.FuncForPC(functionId(action)).Name()
|
||||
}
|
||||
|
||||
func functionId(action func()) uintptr {
|
||||
return reflect.ValueOf(action).Pointer()
|
||||
}
|
16
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/console.go
generated
vendored
16
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/console.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type console struct{}
|
||||
|
||||
func (self *console) Write(p []byte) (n int, err error) {
|
||||
return fmt.Print(string(p))
|
||||
}
|
||||
|
||||
func NewConsole() io.Writer {
|
||||
return new(console)
|
||||
}
|
5
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/doc.go
generated
vendored
5
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/doc.go
generated
vendored
@ -1,5 +0,0 @@
|
||||
// Package reporting contains internal functionality related
|
||||
// to console reporting and output. Although this package has
|
||||
// exported names is not intended for public consumption. See the
|
||||
// examples package for how to use this project.
|
||||
package reporting
|
40
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/dot.go
generated
vendored
40
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/dot.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type dot struct{ out *Printer }
|
||||
|
||||
func (self *dot) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *dot) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *dot) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
fmt.Print(redColor)
|
||||
self.out.Insert(dotError)
|
||||
} else if report.Failure != "" {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(dotFailure)
|
||||
} else if report.Skipped {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(dotSkip)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
self.out.Insert(dotSuccess)
|
||||
}
|
||||
fmt.Print(resetColor)
|
||||
}
|
||||
|
||||
func (self *dot) Exit() {}
|
||||
|
||||
func (self *dot) EndStory() {}
|
||||
|
||||
func (self *dot) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewDotReporter(out *Printer) *dot {
|
||||
self := new(dot)
|
||||
self.out = out
|
||||
return self
|
||||
}
|
40
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/dot_test.go
generated
vendored
40
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/dot_test.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDotReporterAssertionPrinting(t *testing.T) {
|
||||
monochrome()
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
reporter := NewDotReporter(printer)
|
||||
|
||||
reporter.Report(NewSuccessReport())
|
||||
reporter.Report(NewFailureReport("failed"))
|
||||
reporter.Report(NewErrorReport(errors.New("error")))
|
||||
reporter.Report(NewSkipReport())
|
||||
|
||||
expected := dotSuccess + dotFailure + dotError + dotSkip
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("\nExpected: '%s'\nActual: '%s'", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDotReporterOnlyReportsAssertions(t *testing.T) {
|
||||
monochrome()
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
reporter := NewDotReporter(printer)
|
||||
|
||||
reporter.BeginStory(nil)
|
||||
reporter.Enter(nil)
|
||||
reporter.Exit()
|
||||
reporter.EndStory()
|
||||
|
||||
if file.buffer != "" {
|
||||
t.Errorf("\nExpected: '(blank)'\nActual: '%s'", file.buffer)
|
||||
}
|
||||
}
|
33
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/gotest.go
generated
vendored
33
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/gotest.go
generated
vendored
@ -1,33 +0,0 @@
|
||||
package reporting
|
||||
|
||||
type gotestReporter struct{ test T }
|
||||
|
||||
func (self *gotestReporter) BeginStory(story *StoryReport) {
|
||||
self.test = story.Test
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *gotestReporter) Report(r *AssertionResult) {
|
||||
if !passed(r) {
|
||||
self.test.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Exit() {}
|
||||
|
||||
func (self *gotestReporter) EndStory() {
|
||||
self.test = nil
|
||||
}
|
||||
|
||||
func (self *gotestReporter) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewGoTestReporter() *gotestReporter {
|
||||
return new(gotestReporter)
|
||||
}
|
||||
|
||||
func passed(r *AssertionResult) bool {
|
||||
return r.Error == nil && r.Failure == ""
|
||||
}
|
66
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/gotest_test.go
generated
vendored
66
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/gotest_test.go
generated
vendored
@ -1,66 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestReporterReceivesSuccessfulReport(t *testing.T) {
|
||||
reporter := NewGoTestReporter()
|
||||
test := new(fakeTest)
|
||||
reporter.BeginStory(NewStoryReport(test))
|
||||
reporter.Report(NewSuccessReport())
|
||||
|
||||
if test.failed {
|
||||
t.Errorf("Should have have marked test as failed--the report reflected success.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReporterReceivesFailureReport(t *testing.T) {
|
||||
reporter := NewGoTestReporter()
|
||||
test := new(fakeTest)
|
||||
reporter.BeginStory(NewStoryReport(test))
|
||||
reporter.Report(NewFailureReport("This is a failure."))
|
||||
|
||||
if !test.failed {
|
||||
t.Errorf("Test should have been marked as failed (but it wasn't).")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReporterReceivesErrorReport(t *testing.T) {
|
||||
reporter := NewGoTestReporter()
|
||||
test := new(fakeTest)
|
||||
reporter.BeginStory(NewStoryReport(test))
|
||||
reporter.Report(NewErrorReport("This is an error."))
|
||||
|
||||
if !test.failed {
|
||||
t.Errorf("Test should have been marked as failed (but it wasn't).")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReporterIsResetAtTheEndOfTheStory(t *testing.T) {
|
||||
defer catch(t)
|
||||
reporter := NewGoTestReporter()
|
||||
test := new(fakeTest)
|
||||
reporter.BeginStory(NewStoryReport(test))
|
||||
reporter.EndStory()
|
||||
|
||||
reporter.Report(NewSuccessReport())
|
||||
}
|
||||
|
||||
func TestReporterNoopMethods(t *testing.T) {
|
||||
reporter := NewGoTestReporter()
|
||||
reporter.Enter(NewScopeReport("title", "name"))
|
||||
reporter.Exit()
|
||||
}
|
||||
|
||||
func catch(t *testing.T) {
|
||||
if r := recover(); r != nil {
|
||||
t.Log("Getting to this point means we've passed (because we caught a panic appropriately).")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeTest struct {
|
||||
failed bool
|
||||
}
|
||||
|
||||
func (self *fakeTest) Fail() {
|
||||
self.failed = true
|
||||
}
|
94
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/init.go
generated
vendored
94
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/init.go
generated
vendored
@ -1,94 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !isXterm() {
|
||||
monochrome()
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
success, failure, error_ = dotSuccess, dotFailure, dotError
|
||||
}
|
||||
}
|
||||
|
||||
func BuildJsonReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewJsonReporter(out))
|
||||
}
|
||||
func BuildDotReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewDotReporter(out),
|
||||
NewProblemReporter(out),
|
||||
consoleStatistics)
|
||||
}
|
||||
func BuildStoryReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewStoryReporter(out),
|
||||
NewProblemReporter(out),
|
||||
consoleStatistics)
|
||||
}
|
||||
func BuildSilentReporter() Reporter {
|
||||
out := NewPrinter(NewConsole())
|
||||
return NewReporters(
|
||||
NewGoTestReporter(),
|
||||
NewProblemReporter(out))
|
||||
}
|
||||
|
||||
var (
|
||||
newline = "\n"
|
||||
success = "✔"
|
||||
failure = "✘"
|
||||
error_ = "🔥"
|
||||
skip = "⚠"
|
||||
dotSuccess = "."
|
||||
dotFailure = "x"
|
||||
dotError = "E"
|
||||
dotSkip = "S"
|
||||
errorTemplate = "* %s \nLine %d: - %v \n%s\n"
|
||||
failureTemplate = "* %s \nLine %d:\n%s\n"
|
||||
)
|
||||
|
||||
var (
|
||||
greenColor = "\033[32m"
|
||||
yellowColor = "\033[33m"
|
||||
redColor = "\033[31m"
|
||||
resetColor = "\033[0m"
|
||||
)
|
||||
|
||||
var consoleStatistics = NewStatisticsReporter(NewPrinter(NewConsole()))
|
||||
|
||||
// QuiteMode disables all console output symbols. This is only meant to be used
|
||||
// for tests that are internal to goconvey where the output is distracting or
|
||||
// otherwise not needed in the test output.
|
||||
func QuietMode() {
|
||||
success, failure, error_, skip, dotSuccess, dotFailure, dotError, dotSkip = "", "", "", "", "", "", "", ""
|
||||
}
|
||||
|
||||
func monochrome() {
|
||||
greenColor, yellowColor, redColor, resetColor = "", "", "", ""
|
||||
}
|
||||
|
||||
func isXterm() bool {
|
||||
env := fmt.Sprintf("%v", os.Environ())
|
||||
return strings.Contains(env, " TERM=isXterm") ||
|
||||
strings.Contains(env, " TERM=xterm")
|
||||
}
|
||||
|
||||
// This interface allows us to pass the *testing.T struct
|
||||
// throughout the internals of this tool without ever
|
||||
// having to import the "testing" package.
|
||||
type T interface {
|
||||
Fail()
|
||||
}
|
88
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/json.go
generated
vendored
88
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/json.go
generated
vendored
@ -1,88 +0,0 @@
|
||||
// TODO: under unit test
|
||||
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type JsonReporter struct {
|
||||
out *Printer
|
||||
current *ScopeResult
|
||||
index map[string]*ScopeResult
|
||||
scopes []*ScopeResult
|
||||
depth int
|
||||
}
|
||||
|
||||
func (self *JsonReporter) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *JsonReporter) Enter(scope *ScopeReport) {
|
||||
if _, found := self.index[scope.ID]; !found {
|
||||
self.registerScope(scope)
|
||||
}
|
||||
self.depth++
|
||||
self.current = self.index[scope.ID]
|
||||
}
|
||||
func (self *JsonReporter) registerScope(scope *ScopeReport) {
|
||||
next := newScopeResult(scope.Title, self.depth, scope.File, scope.Line)
|
||||
self.scopes = append(self.scopes, next)
|
||||
self.index[scope.ID] = next
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Report(report *AssertionResult) {
|
||||
self.current.Assertions = append(self.current.Assertions, report)
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Exit() {
|
||||
self.depth--
|
||||
}
|
||||
|
||||
func (self *JsonReporter) EndStory() {
|
||||
self.report()
|
||||
self.reset()
|
||||
}
|
||||
func (self *JsonReporter) report() {
|
||||
scopes := []string{}
|
||||
for _, scope := range self.scopes {
|
||||
serialized, err := json.Marshal(scope)
|
||||
if err != nil {
|
||||
self.out.Println(jsonMarshalFailure)
|
||||
panic(err)
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
json.Indent(&buffer, serialized, "", " ")
|
||||
scopes = append(scopes, buffer.String())
|
||||
}
|
||||
self.out.Print(fmt.Sprintf("%s\n%s,\n%s\n", OpenJson, strings.Join(scopes, ","), CloseJson))
|
||||
}
|
||||
func (self *JsonReporter) reset() {
|
||||
self.scopes = []*ScopeResult{}
|
||||
self.index = map[string]*ScopeResult{}
|
||||
self.depth = 0
|
||||
}
|
||||
|
||||
func (self *JsonReporter) Write(content []byte) (written int, err error) {
|
||||
self.current.Output += string(content)
|
||||
return len(content), nil
|
||||
}
|
||||
|
||||
func NewJsonReporter(out *Printer) *JsonReporter {
|
||||
self := new(JsonReporter)
|
||||
self.out = out
|
||||
self.reset()
|
||||
return self
|
||||
}
|
||||
|
||||
const OpenJson = ">>>>>" // "⌦"
|
||||
const CloseJson = "<<<<<" // "⌫"
|
||||
const jsonMarshalFailure = `
|
||||
|
||||
GOCONVEY_JSON_MARSHALL_FAILURE: There was an error when attempting to convert test results to JSON.
|
||||
Please file a bug report and reference the code that caused this failure if possible.
|
||||
|
||||
Here's the panic:
|
||||
|
||||
`
|
57
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/printer.go
generated
vendored
57
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/printer.go
generated
vendored
@ -1,57 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Printer struct {
|
||||
out io.Writer
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (self *Printer) Println(message string, values ...interface{}) {
|
||||
formatted := self.format(message, values...) + newline
|
||||
self.out.Write([]byte(formatted))
|
||||
}
|
||||
|
||||
func (self *Printer) Print(message string, values ...interface{}) {
|
||||
formatted := self.format(message, values...)
|
||||
self.out.Write([]byte(formatted))
|
||||
}
|
||||
|
||||
func (self *Printer) Insert(text string) {
|
||||
self.out.Write([]byte(text))
|
||||
}
|
||||
|
||||
func (self *Printer) format(message string, values ...interface{}) string {
|
||||
var formatted string
|
||||
if len(values) == 0 {
|
||||
formatted = self.prefix + message
|
||||
} else {
|
||||
formatted = self.prefix + fmt.Sprintf(message, values...)
|
||||
}
|
||||
indented := strings.Replace(formatted, newline, newline+self.prefix, -1)
|
||||
return strings.TrimRight(indented, space)
|
||||
}
|
||||
|
||||
func (self *Printer) Indent() {
|
||||
self.prefix += pad
|
||||
}
|
||||
|
||||
func (self *Printer) Dedent() {
|
||||
if len(self.prefix) >= padLength {
|
||||
self.prefix = self.prefix[:len(self.prefix)-padLength]
|
||||
}
|
||||
}
|
||||
|
||||
func NewPrinter(out io.Writer) *Printer {
|
||||
self := new(Printer)
|
||||
self.out = out
|
||||
return self
|
||||
}
|
||||
|
||||
const space = " "
|
||||
const pad = space + space
|
||||
const padLength = len(pad)
|
181
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/printer_test.go
generated
vendored
181
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/printer_test.go
generated
vendored
@ -1,181 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPrint(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "Hello, World!"
|
||||
|
||||
printer.Print(expected)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintFormat(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
template := "Hi, %s"
|
||||
name := "Ralph"
|
||||
expected := "Hi, Ralph"
|
||||
|
||||
printer.Print(template, name)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintPreservesEncodedStrings(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "= -> %3D"
|
||||
printer.Print(expected)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintln(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "Hello, World!"
|
||||
|
||||
printer.Println(expected)
|
||||
|
||||
if file.buffer != expected+"\n" {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintlnFormat(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
template := "Hi, %s"
|
||||
name := "Ralph"
|
||||
expected := "Hi, Ralph\n"
|
||||
|
||||
printer.Println(template, name)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintlnPreservesEncodedStrings(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "= -> %3D"
|
||||
printer.Println(expected)
|
||||
|
||||
if file.buffer != expected+"\n" {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintIndented(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const message = "Hello, World!\nGoodbye, World!"
|
||||
const expected = " Hello, World!\n Goodbye, World!"
|
||||
|
||||
printer.Indent()
|
||||
printer.Print(message)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintDedented(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "Hello, World!\nGoodbye, World!"
|
||||
|
||||
printer.Indent()
|
||||
printer.Dedent()
|
||||
printer.Print(expected)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintlnIndented(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const message = "Hello, World!\nGoodbye, World!"
|
||||
const expected = " Hello, World!\n Goodbye, World!\n"
|
||||
|
||||
printer.Indent()
|
||||
printer.Println(message)
|
||||
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintlnDedented(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
const expected = "Hello, World!\nGoodbye, World!"
|
||||
|
||||
printer.Indent()
|
||||
printer.Dedent()
|
||||
printer.Println(expected)
|
||||
|
||||
if file.buffer != expected+"\n" {
|
||||
t.Errorf("Expected '%s' to equal '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDedentTooFarShouldNotPanic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Error("Should not have panicked!")
|
||||
}
|
||||
}()
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
|
||||
printer.Dedent()
|
||||
|
||||
t.Log("Getting to this point without panicking means we passed.")
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
file := newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
|
||||
printer.Indent()
|
||||
printer.Print("Hi")
|
||||
printer.Insert(" there")
|
||||
printer.Dedent()
|
||||
|
||||
expected := " Hi there"
|
||||
if file.buffer != expected {
|
||||
t.Errorf("Should have written '%s' but instead wrote '%s'.", expected, file.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////// memoryFile ////////////////////
|
||||
|
||||
type memoryFile struct {
|
||||
buffer string
|
||||
}
|
||||
|
||||
func (self *memoryFile) Write(p []byte) (n int, err error) {
|
||||
self.buffer += string(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (self *memoryFile) String() string {
|
||||
return self.buffer
|
||||
}
|
||||
|
||||
func newMemoryFile() *memoryFile {
|
||||
return new(memoryFile)
|
||||
}
|
68
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/problems.go
generated
vendored
68
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/problems.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type problem struct {
|
||||
out *Printer
|
||||
errors []*AssertionResult
|
||||
failures []*AssertionResult
|
||||
}
|
||||
|
||||
func (self *problem) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *problem) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *problem) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
self.errors = append(self.errors, report)
|
||||
} else if report.Failure != "" {
|
||||
self.failures = append(self.failures, report)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *problem) Exit() {}
|
||||
|
||||
func (self *problem) EndStory() {
|
||||
self.show(self.showErrors, redColor)
|
||||
self.show(self.showFailures, yellowColor)
|
||||
self.prepareForNextStory()
|
||||
}
|
||||
func (self *problem) show(display func(), color string) {
|
||||
fmt.Print(color)
|
||||
display()
|
||||
fmt.Print(resetColor)
|
||||
self.out.Dedent()
|
||||
}
|
||||
func (self *problem) showErrors() {
|
||||
for i, e := range self.errors {
|
||||
if i == 0 {
|
||||
self.out.Println("\nErrors:\n")
|
||||
self.out.Indent()
|
||||
}
|
||||
self.out.Println(errorTemplate, e.File, e.Line, e.Error, e.StackTrace)
|
||||
}
|
||||
}
|
||||
func (self *problem) showFailures() {
|
||||
for i, f := range self.failures {
|
||||
if i == 0 {
|
||||
self.out.Println("\nFailures:\n")
|
||||
self.out.Indent()
|
||||
}
|
||||
self.out.Println(failureTemplate, f.File, f.Line, f.Failure)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *problem) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewProblemReporter(out *Printer) *problem {
|
||||
self := new(problem)
|
||||
self.out = out
|
||||
self.prepareForNextStory()
|
||||
return self
|
||||
}
|
||||
func (self *problem) prepareForNextStory() {
|
||||
self.errors = []*AssertionResult{}
|
||||
self.failures = []*AssertionResult{}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNoopProblemReporterActions(t *testing.T) {
|
||||
file, reporter := setup()
|
||||
reporter.BeginStory(nil)
|
||||
reporter.Enter(nil)
|
||||
reporter.Exit()
|
||||
expected := ""
|
||||
actual := file.String()
|
||||
if expected != actual {
|
||||
t.Errorf("Expected: '(blank)'\nActual: '%s'", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReporterPrintsFailuresAndErrorsAtTheEndOfTheStory(t *testing.T) {
|
||||
file, reporter := setup()
|
||||
reporter.Report(NewFailureReport("failed"))
|
||||
reporter.Report(NewErrorReport("error"))
|
||||
reporter.Report(NewSuccessReport())
|
||||
reporter.EndStory()
|
||||
|
||||
result := file.String()
|
||||
if !strings.Contains(result, "Errors:\n") {
|
||||
t.Errorf("Expected errors, found none.")
|
||||
}
|
||||
if !strings.Contains(result, "Failures:\n") {
|
||||
t.Errorf("Expected failures, found none.")
|
||||
}
|
||||
problemCount := strings.Count(result, "*")
|
||||
if problemCount != 2 {
|
||||
t.Errorf("Expected one failure and one error (total of 2 '*' characters). Got %d", problemCount)
|
||||
}
|
||||
}
|
||||
|
||||
func setup() (file *memoryFile, reporter *problem) {
|
||||
monochrome()
|
||||
file = newMemoryFile()
|
||||
printer := NewPrinter(file)
|
||||
reporter = NewProblemReporter(printer)
|
||||
return
|
||||
}
|
39
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/reporter.go
generated
vendored
39
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/reporter.go
generated
vendored
@ -1,39 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "io"
|
||||
|
||||
type Reporter interface {
|
||||
BeginStory(story *StoryReport)
|
||||
Enter(scope *ScopeReport)
|
||||
Report(r *AssertionResult)
|
||||
Exit()
|
||||
EndStory()
|
||||
io.Writer
|
||||
}
|
||||
|
||||
type reporters struct{ collection []Reporter }
|
||||
|
||||
func (self *reporters) BeginStory(s *StoryReport) { self.foreach(func(r Reporter) { r.BeginStory(s) }) }
|
||||
func (self *reporters) Enter(s *ScopeReport) { self.foreach(func(r Reporter) { r.Enter(s) }) }
|
||||
func (self *reporters) Report(a *AssertionResult) { self.foreach(func(r Reporter) { r.Report(a) }) }
|
||||
func (self *reporters) Exit() { self.foreach(func(r Reporter) { r.Exit() }) }
|
||||
func (self *reporters) EndStory() { self.foreach(func(r Reporter) { r.EndStory() }) }
|
||||
|
||||
func (self *reporters) Write(contents []byte) (written int, err error) {
|
||||
self.foreach(func(r Reporter) {
|
||||
written, err = r.Write(contents)
|
||||
})
|
||||
return written, err
|
||||
}
|
||||
|
||||
func (self *reporters) foreach(action func(Reporter)) {
|
||||
for _, r := range self.collection {
|
||||
action(r)
|
||||
}
|
||||
}
|
||||
|
||||
func NewReporters(collection ...Reporter) *reporters {
|
||||
self := new(reporters)
|
||||
self.collection = collection
|
||||
return self
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEachNestedReporterReceivesTheCallFromTheContainingReporter(t *testing.T) {
|
||||
fake1 := newFakeReporter()
|
||||
fake2 := newFakeReporter()
|
||||
reporter := NewReporters(fake1, fake2)
|
||||
|
||||
reporter.BeginStory(nil)
|
||||
assertTrue(t, fake1.begun)
|
||||
assertTrue(t, fake2.begun)
|
||||
|
||||
reporter.Enter(NewScopeReport("scope", "hi"))
|
||||
assertTrue(t, fake1.entered)
|
||||
assertTrue(t, fake2.entered)
|
||||
|
||||
reporter.Report(NewSuccessReport())
|
||||
assertTrue(t, fake1.reported)
|
||||
assertTrue(t, fake2.reported)
|
||||
|
||||
reporter.Exit()
|
||||
assertTrue(t, fake1.exited)
|
||||
assertTrue(t, fake2.exited)
|
||||
|
||||
reporter.EndStory()
|
||||
assertTrue(t, fake1.ended)
|
||||
assertTrue(t, fake2.ended)
|
||||
|
||||
content := []byte("hi")
|
||||
written, err := reporter.Write(content)
|
||||
assertTrue(t, fake1.written)
|
||||
assertTrue(t, fake2.written)
|
||||
assertEqual(t, written, len(content))
|
||||
assertNil(t, err)
|
||||
|
||||
}
|
||||
|
||||
func assertTrue(t *testing.T, value bool) {
|
||||
if !value {
|
||||
_, _, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Value should have been true (but was false). See line %d", line)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqual(t *testing.T, expected, actual int) {
|
||||
if actual != expected {
|
||||
_, _, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Value should have been %d (but was %d). See line %d", expected, actual, line)
|
||||
}
|
||||
}
|
||||
|
||||
func assertNil(t *testing.T, err error) {
|
||||
if err != nil {
|
||||
_, _, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Error should have been <nil> (but wasn't). See line %d", err, line)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeReporter struct {
|
||||
begun bool
|
||||
entered bool
|
||||
reported bool
|
||||
exited bool
|
||||
ended bool
|
||||
written bool
|
||||
}
|
||||
|
||||
func newFakeReporter() *fakeReporter {
|
||||
return &fakeReporter{}
|
||||
}
|
||||
|
||||
func (self *fakeReporter) BeginStory(story *StoryReport) {
|
||||
self.begun = true
|
||||
}
|
||||
func (self *fakeReporter) Enter(scope *ScopeReport) {
|
||||
self.entered = true
|
||||
}
|
||||
func (self *fakeReporter) Report(report *AssertionResult) {
|
||||
self.reported = true
|
||||
}
|
||||
func (self *fakeReporter) Exit() {
|
||||
self.exited = true
|
||||
}
|
||||
func (self *fakeReporter) EndStory() {
|
||||
self.ended = true
|
||||
}
|
||||
func (self *fakeReporter) Write(content []byte) (int, error) {
|
||||
self.written = true
|
||||
return len(content), nil
|
||||
}
|
179
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/reports.go
generated
vendored
179
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/reports.go
generated
vendored
@ -1,179 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/gotest"
|
||||
)
|
||||
|
||||
////////////////// ScopeReport ////////////////////
|
||||
|
||||
type ScopeReport struct {
|
||||
Title string
|
||||
ID string
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func NewScopeReport(title, name string) *ScopeReport {
|
||||
file, line, _ := gotest.ResolveExternalCaller()
|
||||
self := new(ScopeReport)
|
||||
self.Title = title
|
||||
self.ID = fmt.Sprintf("%s|%s", title, name)
|
||||
self.File = file
|
||||
self.Line = line
|
||||
return self
|
||||
}
|
||||
|
||||
////////////////// ScopeResult ////////////////////
|
||||
|
||||
type ScopeResult struct {
|
||||
Title string
|
||||
File string
|
||||
Line int
|
||||
Depth int
|
||||
Assertions []*AssertionResult
|
||||
Output string
|
||||
}
|
||||
|
||||
func newScopeResult(title string, depth int, file string, line int) *ScopeResult {
|
||||
self := new(ScopeResult)
|
||||
self.Title = title
|
||||
self.Depth = depth
|
||||
self.File = file
|
||||
self.Line = line
|
||||
self.Assertions = []*AssertionResult{}
|
||||
return self
|
||||
}
|
||||
|
||||
/////////////////// StoryReport /////////////////////
|
||||
|
||||
type StoryReport struct {
|
||||
Test T
|
||||
Name string
|
||||
File string
|
||||
Line int
|
||||
}
|
||||
|
||||
func NewStoryReport(test T) *StoryReport {
|
||||
file, line, name := gotest.ResolveExternalCaller()
|
||||
name = removePackagePath(name)
|
||||
self := new(StoryReport)
|
||||
self.Test = test
|
||||
self.Name = name
|
||||
self.File = file
|
||||
self.Line = line
|
||||
return self
|
||||
}
|
||||
|
||||
// name comes in looking like "github.com/smartystreets/goconvey/examples.TestName".
|
||||
// We only want the stuff after the last '.', which is the name of the test function.
|
||||
func removePackagePath(name string) string {
|
||||
parts := strings.Split(name, ".")
|
||||
return parts[len(parts)-1]
|
||||
}
|
||||
|
||||
/////////////////// FailureView ////////////////////////
|
||||
|
||||
type FailureView struct {
|
||||
Message string
|
||||
Expected string
|
||||
Actual string
|
||||
}
|
||||
|
||||
////////////////////AssertionResult //////////////////////
|
||||
|
||||
type AssertionResult struct {
|
||||
File string
|
||||
Line int
|
||||
Expected string
|
||||
Actual string
|
||||
Failure string
|
||||
Error interface{}
|
||||
StackTrace string
|
||||
Skipped bool
|
||||
}
|
||||
|
||||
func NewFailureReport(failure string) *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = stackTrace()
|
||||
parseFailure(failure, report)
|
||||
return report
|
||||
}
|
||||
func parseFailure(failure string, report *AssertionResult) {
|
||||
view := new(FailureView)
|
||||
err := json.Unmarshal([]byte(failure), view)
|
||||
if err == nil {
|
||||
report.Failure = view.Message
|
||||
report.Expected = view.Expected
|
||||
report.Actual = view.Actual
|
||||
} else {
|
||||
report.Failure = failure
|
||||
}
|
||||
}
|
||||
func NewErrorReport(err interface{}) *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = fullStackTrace()
|
||||
report.Error = fmt.Sprintf("%v", err)
|
||||
return report
|
||||
}
|
||||
func NewSuccessReport() *AssertionResult {
|
||||
return new(AssertionResult)
|
||||
}
|
||||
func NewSkipReport() *AssertionResult {
|
||||
report := new(AssertionResult)
|
||||
report.File, report.Line = caller()
|
||||
report.StackTrace = fullStackTrace()
|
||||
report.Skipped = true
|
||||
return report
|
||||
}
|
||||
|
||||
func caller() (file string, line int) {
|
||||
file, line, _ = gotest.ResolveExternalCaller()
|
||||
return
|
||||
}
|
||||
|
||||
func stackTrace() string {
|
||||
buffer := make([]byte, 1024*64)
|
||||
n := runtime.Stack(buffer, false)
|
||||
return removeInternalEntries(string(buffer[:n]))
|
||||
}
|
||||
func fullStackTrace() string {
|
||||
buffer := make([]byte, 1024*64)
|
||||
n := runtime.Stack(buffer, true)
|
||||
return removeInternalEntries(string(buffer[:n]))
|
||||
}
|
||||
func removeInternalEntries(stack string) string {
|
||||
lines := strings.Split(stack, newline)
|
||||
filtered := []string{}
|
||||
for _, line := range lines {
|
||||
if !isExternal(line) {
|
||||
filtered = append(filtered, line)
|
||||
}
|
||||
}
|
||||
return strings.Join(filtered, newline)
|
||||
}
|
||||
func isExternal(line string) bool {
|
||||
for _, p := range internalPackages {
|
||||
if strings.Contains(line, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NOTE: any new packages that host goconvey packages will need to be added here!
|
||||
// An alternative is to scan the goconvey directory and then exclude stuff like
|
||||
// the examples package but that's nasty too.
|
||||
var internalPackages = []string{
|
||||
"goconvey/assertions",
|
||||
"goconvey/convey",
|
||||
"goconvey/execution",
|
||||
"goconvey/gotest",
|
||||
"goconvey/reporting",
|
||||
}
|
79
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/statistics.go
generated
vendored
79
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/statistics.go
generated
vendored
@ -1,79 +0,0 @@
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (self *statistics) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *statistics) Enter(scope *ScopeReport) {}
|
||||
|
||||
func (self *statistics) Report(report *AssertionResult) {
|
||||
if !self.failing && report.Failure != "" {
|
||||
self.failing = true
|
||||
}
|
||||
if !self.erroring && report.Error != nil {
|
||||
self.erroring = true
|
||||
}
|
||||
if report.Skipped {
|
||||
self.skipped += 1
|
||||
} else {
|
||||
self.total++
|
||||
}
|
||||
}
|
||||
|
||||
func (self *statistics) Exit() {}
|
||||
|
||||
func (self *statistics) EndStory() {
|
||||
self.reportAssertions()
|
||||
self.reportSkippedSections()
|
||||
self.completeReport()
|
||||
}
|
||||
func (self *statistics) reportAssertions() {
|
||||
self.decideColor()
|
||||
self.out.Print("\n%d %s thus far", self.total, plural("assertion", self.total))
|
||||
}
|
||||
func (self *statistics) decideColor() {
|
||||
if self.failing && !self.erroring {
|
||||
fmt.Print(yellowColor)
|
||||
} else if self.erroring {
|
||||
fmt.Print(redColor)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
}
|
||||
}
|
||||
func (self *statistics) reportSkippedSections() {
|
||||
if self.skipped > 0 {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Print(" (one or more sections skipped)")
|
||||
self.skipped = 0
|
||||
}
|
||||
}
|
||||
func (self *statistics) completeReport() {
|
||||
fmt.Print(resetColor)
|
||||
self.out.Print("\n")
|
||||
self.out.Print("\n")
|
||||
}
|
||||
|
||||
func (self *statistics) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewStatisticsReporter(out *Printer) *statistics {
|
||||
self := statistics{}
|
||||
self.out = out
|
||||
return &self
|
||||
}
|
||||
|
||||
type statistics struct {
|
||||
out *Printer
|
||||
total int
|
||||
failing bool
|
||||
erroring bool
|
||||
skipped int
|
||||
}
|
||||
|
||||
func plural(word string, count int) string {
|
||||
if count == 1 {
|
||||
return word
|
||||
}
|
||||
return word + "s"
|
||||
}
|
65
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/story.go
generated
vendored
65
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting/story.go
generated
vendored
@ -1,65 +0,0 @@
|
||||
// TODO: in order for this reporter to be completely honest
|
||||
// we need to retrofit to be more like the json reporter such that:
|
||||
// 1. it maintains ScopeResult collections, which count assertions
|
||||
// 2. it reports only after EndStory(), so that all tick marks
|
||||
// are placed near the appropriate title.
|
||||
// 3. Under unit test
|
||||
|
||||
package reporting
|
||||
|
||||
import "fmt"
|
||||
|
||||
type story struct {
|
||||
out *Printer
|
||||
titlesById map[string]string
|
||||
}
|
||||
|
||||
func (self *story) BeginStory(story *StoryReport) {}
|
||||
|
||||
func (self *story) Enter(scope *ScopeReport) {
|
||||
self.out.Indent()
|
||||
|
||||
if _, found := self.titlesById[scope.ID]; !found {
|
||||
self.out.Println("")
|
||||
self.out.Print(scope.Title)
|
||||
self.out.Insert(" ")
|
||||
self.titlesById[scope.ID] = scope.Title
|
||||
}
|
||||
}
|
||||
|
||||
func (self *story) Report(report *AssertionResult) {
|
||||
if report.Error != nil {
|
||||
fmt.Print(redColor)
|
||||
self.out.Insert(error_)
|
||||
} else if report.Failure != "" {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(failure)
|
||||
} else if report.Skipped {
|
||||
fmt.Print(yellowColor)
|
||||
self.out.Insert(skip)
|
||||
} else {
|
||||
fmt.Print(greenColor)
|
||||
self.out.Insert(success)
|
||||
}
|
||||
fmt.Print(resetColor)
|
||||
}
|
||||
|
||||
func (self *story) Exit() {
|
||||
self.out.Dedent()
|
||||
}
|
||||
|
||||
func (self *story) EndStory() {
|
||||
self.titlesById = make(map[string]string)
|
||||
self.out.Println("\n")
|
||||
}
|
||||
|
||||
func (self *story) Write(content []byte) (written int, err error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func NewStoryReporter(out *Printer) *story {
|
||||
self := new(story)
|
||||
self.out = out
|
||||
self.titlesById = make(map[string]string)
|
||||
return self
|
||||
}
|
270
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting_hooks_test.go
generated
vendored
270
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/reporting_hooks_test.go
generated
vendored
@ -1,270 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
func TestSingleScopeReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
So(1, ShouldEqual, 1)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Success|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestNestedScopeReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
Convey("B", func() {
|
||||
So(1, ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|B|Success|Exit|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestFailureReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
So(1, ShouldBeNil)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Failure|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestFirstFailureEndsScopeExecution(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
So(1, ShouldBeNil)
|
||||
So(nil, ShouldBeNil)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Failure|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestComparisonFailureDeserializedAndReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
So("hi", ShouldEqual, "bye")
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Failure(bye/hi)|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestNestedFailureReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
Convey("B", func() {
|
||||
So(2, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|B|Failure|Exit|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestSuccessAndFailureReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
So(nil, ShouldBeNil)
|
||||
So(1, ShouldBeNil)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Success|Failure|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestIncompleteActionReportedAsSkipped(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
Convey("B", nil)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|B|Skipped|Exit|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestSkippedConveyReportedAsSkipped(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
SkipConvey("B", func() {
|
||||
So(1, ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|B|Skipped|Exit|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestMultipleSkipsAreReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
Convey("0", func() {
|
||||
So(nil, ShouldBeNil)
|
||||
})
|
||||
|
||||
SkipConvey("1", func() {})
|
||||
SkipConvey("2", func() {})
|
||||
|
||||
Convey("3", nil)
|
||||
Convey("4", nil)
|
||||
|
||||
Convey("5", func() {
|
||||
So(nil, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
expected := "Begin" +
|
||||
"|A|0|Success|Exit|Exit" +
|
||||
"|A|1|Skipped|Exit|Exit" +
|
||||
"|A|2|Skipped|Exit|Exit" +
|
||||
"|A|3|Skipped|Exit|Exit" +
|
||||
"|A|4|Skipped|Exit|Exit" +
|
||||
"|A|5|Success|Exit|Exit" +
|
||||
"|End"
|
||||
|
||||
expectEqual(t, expected, myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestSkippedAssertionIsNotReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
SkipSo(1, ShouldEqual, 1)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Skipped|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestMultipleSkippedAssertionsAreNotReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
SkipSo(1, ShouldEqual, 1)
|
||||
So(1, ShouldEqual, 1)
|
||||
SkipSo(1, ShouldEqual, 1)
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Skipped|Success|Skipped|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestErrorByManualPanicReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
panic("Gopher alert!")
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Error|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestIterativeConveysReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
for x := 0; x < 3; x++ {
|
||||
Convey(strconv.Itoa(x), func() {
|
||||
So(x, ShouldEqual, x)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|0|Success|Exit|Exit|A|1|Success|Exit|Exit|A|2|Success|Exit|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func TestEmbeddedAssertionReported(t *testing.T) {
|
||||
myReporter, test := setupFakeReporter()
|
||||
|
||||
Convey("A", test, func() {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
So(r.FormValue("msg"), ShouldEqual, "ping")
|
||||
}))
|
||||
http.DefaultClient.Get(ts.URL + "?msg=ping")
|
||||
})
|
||||
|
||||
expectEqual(t, "Begin|A|Success|Exit|End", myReporter.wholeStory())
|
||||
}
|
||||
|
||||
func expectEqual(t *testing.T, expected interface{}, actual interface{}) {
|
||||
if expected != actual {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
t.Errorf("Expected '%v' to be '%v' but it wasn't. See '%s' at line %d.",
|
||||
actual, expected, path.Base(file), line)
|
||||
}
|
||||
}
|
||||
|
||||
func setupFakeReporter() (*fakeReporter, *fakeGoTest) {
|
||||
myReporter := new(fakeReporter)
|
||||
myReporter.calls = []string{}
|
||||
testReporter = myReporter
|
||||
return myReporter, new(fakeGoTest)
|
||||
}
|
||||
|
||||
type fakeReporter struct {
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (self *fakeReporter) BeginStory(story *reporting.StoryReport) {
|
||||
self.calls = append(self.calls, "Begin")
|
||||
}
|
||||
|
||||
func (self *fakeReporter) Enter(scope *reporting.ScopeReport) {
|
||||
self.calls = append(self.calls, scope.Title)
|
||||
}
|
||||
|
||||
func (self *fakeReporter) Report(report *reporting.AssertionResult) {
|
||||
if report.Error != nil {
|
||||
self.calls = append(self.calls, "Error")
|
||||
} else if report.Failure != "" {
|
||||
message := "Failure"
|
||||
if report.Expected != "" || report.Actual != "" {
|
||||
message += fmt.Sprintf("(%s/%s)", report.Expected, report.Actual)
|
||||
}
|
||||
self.calls = append(self.calls, message)
|
||||
} else if report.Skipped {
|
||||
self.calls = append(self.calls, "Skipped")
|
||||
} else {
|
||||
self.calls = append(self.calls, "Success")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *fakeReporter) Exit() {
|
||||
self.calls = append(self.calls, "Exit")
|
||||
}
|
||||
|
||||
func (self *fakeReporter) EndStory() {
|
||||
self.calls = append(self.calls, "End")
|
||||
}
|
||||
|
||||
func (self *fakeReporter) Write(content []byte) (int, error) {
|
||||
return len(content), nil // no-op
|
||||
}
|
||||
|
||||
func (self *fakeReporter) wholeStory() string {
|
||||
return strings.Join(self.calls, "|")
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
type fakeGoTest struct{}
|
||||
|
||||
func (self *fakeGoTest) Fail() {}
|
||||
func (self *fakeGoTest) Fatalf(format string, args ...interface{}) {}
|
||||
|
||||
var test t = new(fakeGoTest)
|
92
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/runner.go
generated
vendored
92
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/runner.go
generated
vendored
@ -1,92 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type runner struct {
|
||||
top *scope
|
||||
active *scope
|
||||
reporter reporting.Reporter
|
||||
failureMode FailureMode
|
||||
focus bool
|
||||
}
|
||||
|
||||
func (self *runner) Register(entry *registration) {
|
||||
if self.focus && !entry.Focus {
|
||||
return
|
||||
}
|
||||
|
||||
self.active.adopt(newScope(entry, self.reporter))
|
||||
}
|
||||
|
||||
func (self *runner) RegisterReset(action *action) {
|
||||
self.active.registerReset(action)
|
||||
}
|
||||
|
||||
func (self *runner) Run(entry *registration) {
|
||||
self.active = self.top
|
||||
self.focus = entry.Focus
|
||||
self.failureMode = defaultFailureMode
|
||||
|
||||
self.Register(entry)
|
||||
self.reporter.BeginStory(reporting.NewStoryReport(entry.Test))
|
||||
|
||||
for !self.top.visited() {
|
||||
self.top.visit(self)
|
||||
}
|
||||
|
||||
self.reporter.EndStory()
|
||||
}
|
||||
|
||||
func newRunner(reporter reporting.Reporter) *runner {
|
||||
// Top-level is always using a nilReporter
|
||||
scope := newScope(newRegistration(topLevel, newAction(func() {}, FailureInherits), nil), newNilReporter())
|
||||
|
||||
return &runner{
|
||||
reporter: reporter,
|
||||
top: scope,
|
||||
active: scope,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *runner) Report(result *reporting.AssertionResult) {
|
||||
self.reporter.Report(result)
|
||||
|
||||
if result.Failure != "" && self.failureMode == FailureHalts {
|
||||
panic(failureHalt)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *runner) Write(content []byte) (written int, err error) {
|
||||
return self.reporter.Write(content)
|
||||
}
|
||||
|
||||
func (self *runner) setFailureMode(mode FailureMode) FailureMode {
|
||||
old := self.failureMode
|
||||
|
||||
if mode != FailureInherits {
|
||||
self.failureMode = mode
|
||||
}
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
func last(group []string) string {
|
||||
return group[len(group)-1]
|
||||
}
|
||||
|
||||
const topLevel = "TOP"
|
||||
const failureHalt = "___FAILURE_HALT___"
|
||||
|
||||
//////////////////////// nilReporter /////////////////////////////
|
||||
|
||||
type nilReporter struct{}
|
||||
|
||||
func (self *nilReporter) BeginStory(story *reporting.StoryReport) {}
|
||||
func (self *nilReporter) Enter(scope *reporting.ScopeReport) {}
|
||||
func (self *nilReporter) Report(report *reporting.AssertionResult) {}
|
||||
func (self *nilReporter) Exit() {}
|
||||
func (self *nilReporter) EndStory() {}
|
||||
func (self *nilReporter) Write(p []byte) (int, error) { return len(p), nil }
|
||||
func newNilReporter() *nilReporter { return &nilReporter{} }
|
116
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/scope.go
generated
vendored
116
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/scope.go
generated
vendored
@ -1,116 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/smartystreets/goconvey/convey/reporting"
|
||||
)
|
||||
|
||||
type scope struct {
|
||||
name string
|
||||
title string
|
||||
action *action
|
||||
children map[string]*scope
|
||||
birthOrder []*scope
|
||||
child int
|
||||
resetOrder []string
|
||||
resets map[string]*action
|
||||
panicked bool
|
||||
reporter reporting.Reporter
|
||||
report *reporting.ScopeReport
|
||||
}
|
||||
|
||||
func (parent *scope) adopt(child *scope) {
|
||||
i := parent.getChildIndex(child)
|
||||
|
||||
if i == -1 {
|
||||
parent.children[child.name] = child
|
||||
parent.birthOrder = append(parent.birthOrder, child)
|
||||
} else {
|
||||
/* We need to replace the action to retain the closed over variables from
|
||||
the specific invocation of the parent scope, enabling the enclosing
|
||||
parent scope to serve as a set-up for the child scope */
|
||||
parent.birthOrder[i].action = child.action
|
||||
}
|
||||
}
|
||||
|
||||
func (parent *scope) getChildIndex(child *scope) int {
|
||||
for i, ordered := range parent.birthOrder {
|
||||
if ordered.name == child.name && ordered.title == child.title {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func (self *scope) registerReset(action *action) {
|
||||
self.resets[action.name] = action
|
||||
for _, name := range self.resetOrder {
|
||||
if name == action.name {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.resetOrder = append(self.resetOrder, action.name)
|
||||
}
|
||||
|
||||
func (self *scope) visited() bool {
|
||||
return self.panicked || self.child >= len(self.birthOrder)
|
||||
}
|
||||
|
||||
func (parent *scope) visit(runner *runner) {
|
||||
runner.active = parent
|
||||
defer parent.exit()
|
||||
|
||||
oldMode := runner.setFailureMode(parent.action.failureMode)
|
||||
defer runner.setFailureMode(oldMode)
|
||||
|
||||
parent.reporter.Enter(parent.report)
|
||||
parent.action.Invoke()
|
||||
parent.visitNextChild(runner)
|
||||
parent.cleanup()
|
||||
}
|
||||
func (parent *scope) visitNextChild(runner *runner) {
|
||||
if len(parent.birthOrder) > parent.child {
|
||||
child := parent.birthOrder[parent.child]
|
||||
|
||||
child.visit(runner)
|
||||
|
||||
if child.visited() {
|
||||
parent.child++
|
||||
}
|
||||
}
|
||||
}
|
||||
func (parent *scope) cleanup() {
|
||||
for _, name := range parent.resetOrder {
|
||||
reset := parent.resets[name]
|
||||
reset.Invoke()
|
||||
}
|
||||
}
|
||||
func (parent *scope) exit() {
|
||||
if problem := recover(); problem != nil {
|
||||
if strings.HasPrefix(fmt.Sprintf("%v", problem), extraGoTest) {
|
||||
panic(problem)
|
||||
}
|
||||
if problem != failureHalt {
|
||||
parent.reporter.Report(reporting.NewErrorReport(problem))
|
||||
}
|
||||
parent.panicked = true
|
||||
}
|
||||
parent.reporter.Exit()
|
||||
}
|
||||
|
||||
func newScope(entry *registration, reporter reporting.Reporter) *scope {
|
||||
return &scope{
|
||||
reporter: reporter,
|
||||
name: entry.action.name,
|
||||
title: entry.Situation,
|
||||
action: entry.action,
|
||||
children: make(map[string]*scope),
|
||||
birthOrder: []*scope{},
|
||||
resetOrder: []string{},
|
||||
resets: make(map[string]*action),
|
||||
report: reporting.NewScopeReport(entry.Situation, entry.action.name),
|
||||
}
|
||||
}
|
185
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/story_conventions_test.go
generated
vendored
185
Godeps/_workspace/src/github.com/smartystreets/goconvey/convey/story_conventions_test.go
generated
vendored
@ -1,185 +0,0 @@
|
||||
package convey
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMissingTopLevelGoTestReferenceCausesPanic(t *testing.T) {
|
||||
output := map[string]bool{}
|
||||
|
||||
defer expectEqual(t, false, output["good"])
|
||||
defer requireGoTestReference(t)
|
||||
|
||||
Convey("Hi", func() {
|
||||
output["bad"] = true // this shouldn't happen
|
||||
})
|
||||
}
|
||||
|
||||
func requireGoTestReference(t *testing.T) {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Error("We should have recovered a panic here (because of a missing *testing.T reference)!")
|
||||
} else {
|
||||
expectEqual(t, missingGoTest, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMissingTopLevelGoTestReferenceAfterGoodExample(t *testing.T) {
|
||||
output := map[string]bool{}
|
||||
|
||||
defer func() {
|
||||
expectEqual(t, true, output["good"])
|
||||
expectEqual(t, false, output["bad"])
|
||||
}()
|
||||
defer requireGoTestReference(t)
|
||||
|
||||
Convey("Good example", t, func() {
|
||||
output["good"] = true
|
||||
})
|
||||
|
||||
Convey("Bad example", func() {
|
||||
output["bad"] = true // shouldn't happen
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtraReferencePanics(t *testing.T) {
|
||||
output := map[string]bool{}
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err == nil {
|
||||
t.Error("We should have recovered a panic here (because of an extra *testing.T reference)!")
|
||||
} else if !strings.HasPrefix(fmt.Sprintf("%v", err), extraGoTest) {
|
||||
t.Error("Should have panicked with the 'extra go test' error!")
|
||||
}
|
||||
if output["bad"] {
|
||||
t.Error("We should NOT have run the bad example!")
|
||||
}
|
||||
}()
|
||||
|
||||
Convey("Good example", t, func() {
|
||||
Convey("Bad example - passing in *testing.T a second time!", t, func() {
|
||||
output["bad"] = true // shouldn't happen
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseRegistrationMissingRequiredElements(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != "You must provide a name (string), then a *testing.T (if in outermost scope), an optional FailureMode, and then an action (func())." {
|
||||
t.Errorf("Incorrect panic message.")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Convey()
|
||||
|
||||
t.Errorf("goTest should have panicked in Convey(...) and then recovered in the defer func().")
|
||||
}
|
||||
|
||||
func TestParseRegistration_MissingNameString(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != parseError {
|
||||
t.Errorf("Incorrect panic message.")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
action := func() {}
|
||||
|
||||
Convey(action)
|
||||
|
||||
t.Errorf("goTest should have panicked in Convey(...) and then recovered in the defer func().")
|
||||
}
|
||||
|
||||
func TestParseRegistration_MissingActionFunc(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != parseError {
|
||||
t.Errorf("Incorrect panic message: '%s'", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Convey("Hi there", 12345)
|
||||
|
||||
t.Errorf("goTest should have panicked in Convey(...) and then recovered in the defer func().")
|
||||
}
|
||||
|
||||
func TestFailureModeParameterButMissing(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != parseError {
|
||||
t.Errorf("Incorrect panic message.")
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected panic")
|
||||
}
|
||||
}()
|
||||
|
||||
prepare()
|
||||
|
||||
Convey("Foobar", t, FailureHalts)
|
||||
}
|
||||
|
||||
func TestFailureModeParameterWithAction(t *testing.T) {
|
||||
prepare()
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("Unexpected panic")
|
||||
}
|
||||
}()
|
||||
|
||||
Convey("Foobar", t, FailureHalts, func() {})
|
||||
}
|
||||
|
||||
func TestExtraConveyParameters(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != parseError {
|
||||
t.Errorf("Incorrect panic message.")
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected panic")
|
||||
}
|
||||
}()
|
||||
|
||||
prepare()
|
||||
|
||||
Convey("Foobar", t, FailureHalts, func() {}, "This is not supposed to be here")
|
||||
}
|
||||
|
||||
func TestExtraConveyParameters2(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if r != parseError {
|
||||
t.Errorf("Incorrect panic message.")
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Expected panic")
|
||||
}
|
||||
}()
|
||||
|
||||
prepare()
|
||||
|
||||
Convey("Foobar", t, func() {}, "This is not supposed to be here")
|
||||
}
|
||||
|
||||
func TestExtraConveyParameters3(t *testing.T) {
|
||||
output := prepare()
|
||||
|
||||
Convey("A", t, func() {
|
||||
output += "A "
|
||||
|
||||
Convey("B", func() {
|
||||
output += "B "
|
||||
}, "This is not supposed to be here")
|
||||
})
|
||||
|
||||
expectEqual(t, "A ", output)
|
||||
}
|
93
Godeps/_workspace/src/gopkg.in/ini.v1/README.md
generated
vendored
93
Godeps/_workspace/src/gopkg.in/ini.v1/README.md
generated
vendored
@ -121,11 +121,15 @@ v, err = cfg.Section("").Key("BOOL").Bool()
|
||||
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||
v, err = cfg.Section("").Key("INT").Int()
|
||||
v, err = cfg.Section("").Key("INT64").Int64()
|
||||
v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
|
||||
v, err = cfg.Section("").Key("TIME").Time() // RFC3339
|
||||
|
||||
v = cfg.Section("").Key("BOOL").MustBool()
|
||||
v = cfg.Section("").Key("FLOAT64").MustFloat64()
|
||||
v = cfg.Section("").Key("INT").MustInt()
|
||||
v = cfg.Section("").Key("INT64").MustInt64()
|
||||
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
|
||||
v = cfg.Section("").Key("TIME").MustTime() // RFC3339
|
||||
|
||||
// Methods start with Must also accept one argument for default value
|
||||
// when key not found or fail to parse value to given type.
|
||||
@ -136,6 +140,8 @@ v = cfg.Section("").Key("BOOL").MustBool(true)
|
||||
v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
|
||||
v = cfg.Section("").Key("INT").MustInt(10)
|
||||
v = cfg.Section("").Key("INT64").MustInt64(99)
|
||||
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
|
||||
v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339
|
||||
```
|
||||
|
||||
What if my value is three-line long?
|
||||
@ -170,6 +176,7 @@ v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3})
|
||||
```
|
||||
|
||||
Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates.
|
||||
@ -181,11 +188,12 @@ vals = cfg.Section("").Key("STRINGS").Strings(",")
|
||||
vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
|
||||
vals = cfg.Section("").Key("INTS").Ints(",")
|
||||
vals = cfg.Section("").Key("INT64S").Int64s(",")
|
||||
vals = cfg.Section("").Key("TIMES").Times(",")
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
## Advanced Usage
|
||||
|
||||
#### Recursive Values
|
||||
### Recursive Values
|
||||
|
||||
For all value of keys, there is a special syntax `%(<name>)s`, where `<name>` is the key name in same section or default section, and `%(<name>)s` will be replaced by corresponding value(empty string if key not found). You can use this syntax at most 99 level of recursions.
|
||||
|
||||
@ -205,7 +213,7 @@ cfg.Section("author").Key("GITHUB").String() // https://github.com/Unknwon
|
||||
cfg.Section("package").Key("FULL_NAME").String() // github.com/go-ini/ini
|
||||
```
|
||||
|
||||
#### Parent-child Sections
|
||||
### Parent-child Sections
|
||||
|
||||
You can use `.` in section name to indicate parent-child relationship between two or more sections. If the key not found in the child section, library will try again on its parent section until there is no parent section.
|
||||
|
||||
@ -224,7 +232,7 @@ CLONE_URL = https://%(IMPORT_PATH)s
|
||||
cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1
|
||||
```
|
||||
|
||||
#### Auto-increment Key Names
|
||||
### Auto-increment Key Names
|
||||
|
||||
If key name is `-` in data source, then it would be seen as special syntax for auto-increment key name start from 1, and every section is independent on counter.
|
||||
|
||||
@ -239,6 +247,83 @@ If key name is `-` in data source, then it would be seen as special syntax for a
|
||||
cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"}
|
||||
```
|
||||
|
||||
### Map To Struct
|
||||
|
||||
Want more objective way to play with INI? Cool.
|
||||
|
||||
```ini
|
||||
Name = Unknwon
|
||||
age = 21
|
||||
Male = true
|
||||
Born = 1993-01-01T20:17:05Z
|
||||
|
||||
[Note]
|
||||
Content = Hi is a good man!
|
||||
Cities = HangZhou, Boston
|
||||
```
|
||||
|
||||
```go
|
||||
type Note struct {
|
||||
Content string
|
||||
Cities []string
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int `ini:"age"`
|
||||
Male bool
|
||||
Born time.Time
|
||||
Note
|
||||
Created time.Time `ini:"-"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, err := ini.Load("path/to/ini")
|
||||
// ...
|
||||
p := new(Person)
|
||||
err = cfg.MapTo(p)
|
||||
// ...
|
||||
|
||||
// Things can be simpler.
|
||||
err = ini.MapTo(p, "path/to/ini")
|
||||
// ...
|
||||
|
||||
// Just map a section? Fine.
|
||||
n := new(Note)
|
||||
err = cfg.Section("Note").MapTo(n)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Name Mapper
|
||||
|
||||
To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual secion and key name.
|
||||
|
||||
There are 2 built-in name mappers:
|
||||
|
||||
- `AllCapsUnderscore`: it converts to format `ALL_CAPS_UNDERSCORE` then match section or key.
|
||||
- `TitleUnderscore`: it converts to format `title_underscore` then match section or key.
|
||||
|
||||
To use them:
|
||||
|
||||
```go
|
||||
type Info struct{
|
||||
PackageName string
|
||||
}
|
||||
|
||||
func main() {
|
||||
err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("packag_name=ini"))
|
||||
// ...
|
||||
|
||||
cfg, err := ini.Load("PACKAGE_NAME=ini")
|
||||
// ...
|
||||
info := new(Info)
|
||||
cfg.NameMapper = ini.AllCapsUnderscore
|
||||
err = cfg.MapTo(info)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [API Documentation](https://gowalker.org/gopkg.in/ini.v1)
|
||||
|
85
Godeps/_workspace/src/gopkg.in/ini.v1/README_ZH.md
generated
vendored
85
Godeps/_workspace/src/gopkg.in/ini.v1/README_ZH.md
generated
vendored
@ -116,11 +116,15 @@ v, err = cfg.Section("").Key("BOOL").Bool()
|
||||
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||
v, err = cfg.Section("").Key("INT").Int()
|
||||
v, err = cfg.Section("").Key("INT64").Int64()
|
||||
v, err = cfg.Section("").Key("TIME").TimeFormat(time.RFC3339)
|
||||
v, err = cfg.Section("").Key("TIME").Time() // RFC3339
|
||||
|
||||
v = cfg.Section("").Key("BOOL").MustBool()
|
||||
v = cfg.Section("").Key("FLOAT64").MustFloat64()
|
||||
v = cfg.Section("").Key("INT").MustInt()
|
||||
v = cfg.Section("").Key("INT64").MustInt64()
|
||||
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339)
|
||||
v = cfg.Section("").Key("TIME").MustTime() // RFC3339
|
||||
|
||||
// 由 Must 开头的方法名允许接收一个相同类型的参数来作为默认值,
|
||||
// 当键不存在或者转换失败时,则会直接返回该默认值。
|
||||
@ -131,6 +135,8 @@ v = cfg.Section("").Key("BOOL").MustBool(true)
|
||||
v = cfg.Section("").Key("FLOAT64").MustFloat64(1.25)
|
||||
v = cfg.Section("").Key("INT").MustInt(10)
|
||||
v = cfg.Section("").Key("INT64").MustInt64(99)
|
||||
v = cfg.Section("").Key("TIME").MustTimeFormat(time.RFC3339, time.Now())
|
||||
v = cfg.Section("").Key("TIME").MustTime(time.Now()) // RFC3339
|
||||
```
|
||||
|
||||
如果我的值有好多行怎么办?
|
||||
@ -165,6 +171,7 @@ v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3})
|
||||
```
|
||||
|
||||
如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。
|
||||
@ -176,6 +183,7 @@ vals = cfg.Section("").Key("STRINGS").Strings(",")
|
||||
vals = cfg.Section("").Key("FLOAT64S").Float64s(",")
|
||||
vals = cfg.Section("").Key("INTS").Ints(",")
|
||||
vals = cfg.Section("").Key("INT64S").Int64s(",")
|
||||
vals = cfg.Section("").Key("TIMES").Times(",")
|
||||
```
|
||||
|
||||
### 高级用法
|
||||
@ -234,6 +242,83 @@ cfg.Section("package.sub").Key("CLONE_URL").String() // https://gopkg.in/ini.v1
|
||||
cfg.Section("features").KeyStrings() // []{"#1", "#2", "#3"}
|
||||
```
|
||||
|
||||
### 映射到结构
|
||||
|
||||
想要使用更加面向对象的方式玩转 INI 吗?好主意。
|
||||
|
||||
```ini
|
||||
Name = Unknwon
|
||||
age = 21
|
||||
Male = true
|
||||
Born = 1993-01-01T20:17:05Z
|
||||
|
||||
[Note]
|
||||
Content = Hi is a good man!
|
||||
Cities = HangZhou, Boston
|
||||
```
|
||||
|
||||
```go
|
||||
type Note struct {
|
||||
Content string
|
||||
Cities []string
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int `ini:"age"`
|
||||
Male bool
|
||||
Born time.Time
|
||||
Note
|
||||
Created time.Time `ini:"-"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg, err := ini.Load("path/to/ini")
|
||||
// ...
|
||||
p := new(Person)
|
||||
err = cfg.MapTo(p)
|
||||
// ...
|
||||
|
||||
// 一切竟可以如此的简单。
|
||||
err = ini.MapTo(p, "path/to/ini")
|
||||
// ...
|
||||
|
||||
// 嗯哼?只需要映射一个分区吗?
|
||||
n := new(Note)
|
||||
err = cfg.Section("Note").MapTo(n)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### 名称映射器(Name Mapper)
|
||||
|
||||
为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。
|
||||
|
||||
目前有 2 款内置的映射器:
|
||||
|
||||
- `AllCapsUnderscore`:该映射器将字段名转换至格式 `ALL_CAPS_UNDERSCORE` 后再去匹配分区名和键名。
|
||||
- `TitleUnderscore`:该映射器将字段名转换至格式 `title_underscore` 后再去匹配分区名和键名。
|
||||
|
||||
使用方法:
|
||||
|
||||
```go
|
||||
type Info struct{
|
||||
PackageName string
|
||||
}
|
||||
|
||||
func main() {
|
||||
err = ini.MapToWithMapper(&Info{}, ini.TitleUnderscore, []byte("packag_name=ini"))
|
||||
// ...
|
||||
|
||||
cfg, err := ini.Load("PACKAGE_NAME=ini")
|
||||
// ...
|
||||
info := new(Info)
|
||||
cfg.NameMapper = ini.AllCapsUnderscore
|
||||
err = cfg.MapTo(info)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 获取帮助
|
||||
|
||||
- [API 文档](https://gowalker.org/gopkg.in/ini.v1)
|
||||
|
91
Godeps/_workspace/src/gopkg.in/ini.v1/ini.go
generated
vendored
91
Godeps/_workspace/src/gopkg.in/ini.v1/ini.go
generated
vendored
@ -27,14 +27,21 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_SECTION = "DEFAULT"
|
||||
// Maximum allowed depth when recursively substituing variable names.
|
||||
_DEPTH_VALUES = 99
|
||||
|
||||
_VERSION = "1.0.1"
|
||||
)
|
||||
|
||||
func Version() string {
|
||||
return _VERSION
|
||||
}
|
||||
|
||||
var (
|
||||
LineBreak = "\n"
|
||||
|
||||
@ -157,6 +164,16 @@ func (k *Key) Int64() (int64, error) {
|
||||
return strconv.ParseInt(k.String(), 10, 64)
|
||||
}
|
||||
|
||||
// TimeFormat parses with given format and returns time.Time type value.
|
||||
func (k *Key) TimeFormat(format string) (time.Time, error) {
|
||||
return time.Parse(format, k.String())
|
||||
}
|
||||
|
||||
// Time parses with RFC3339 format and returns time.Time type value.
|
||||
func (k *Key) Time() (time.Time, error) {
|
||||
return k.TimeFormat(time.RFC3339)
|
||||
}
|
||||
|
||||
// MustString returns default value if key value is empty.
|
||||
func (k *Key) MustString(defaultVal string) string {
|
||||
val := k.String()
|
||||
@ -179,31 +196,47 @@ func (k *Key) MustBool(defaultVal ...bool) bool {
|
||||
// MustFloat64 always returns value without error,
|
||||
// it returns 0.0 if error occurs.
|
||||
func (k *Key) MustFloat64(defaultVal ...float64) float64 {
|
||||
value, err := k.Float64()
|
||||
val, err := k.Float64()
|
||||
if len(defaultVal) > 0 && err != nil {
|
||||
return defaultVal[0]
|
||||
}
|
||||
return value
|
||||
return val
|
||||
}
|
||||
|
||||
// MustInt always returns value without error,
|
||||
// it returns 0 if error occurs.
|
||||
func (k *Key) MustInt(defaultVal ...int) int {
|
||||
value, err := k.Int()
|
||||
val, err := k.Int()
|
||||
if len(defaultVal) > 0 && err != nil {
|
||||
return defaultVal[0]
|
||||
}
|
||||
return value
|
||||
return val
|
||||
}
|
||||
|
||||
// MustInt64 always returns value without error,
|
||||
// it returns 0 if error occurs.
|
||||
func (k *Key) MustInt64(defaultVal ...int64) int64 {
|
||||
value, err := k.Int64()
|
||||
val, err := k.Int64()
|
||||
if len(defaultVal) > 0 && err != nil {
|
||||
return defaultVal[0]
|
||||
}
|
||||
return value
|
||||
return val
|
||||
}
|
||||
|
||||
// MustTimeFormat always parses with given format and returns value without error,
|
||||
// it returns zero value if error occurs.
|
||||
func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time {
|
||||
val, err := k.TimeFormat(format)
|
||||
if len(defaultVal) > 0 && err != nil {
|
||||
return defaultVal[0]
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustTime always parses with RFC3339 format and returns value without error,
|
||||
// it returns zero value if error occurs.
|
||||
func (k *Key) MustTime(defaultVal ...time.Time) time.Time {
|
||||
return k.MustTimeFormat(time.RFC3339, defaultVal...)
|
||||
}
|
||||
|
||||
// In always returns value without error,
|
||||
@ -218,7 +251,7 @@ func (k *Key) In(defaultVal string, candidates []string) string {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// In always returns value without error,
|
||||
// InFloat64 always returns value without error,
|
||||
// it returns default value if error occurs or doesn't fit into candidates.
|
||||
func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 {
|
||||
val := k.MustFloat64()
|
||||
@ -230,7 +263,7 @@ func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// In always returns value without error,
|
||||
// InInt always returns value without error,
|
||||
// it returns default value if error occurs or doesn't fit into candidates.
|
||||
func (k *Key) InInt(defaultVal int, candidates []int) int {
|
||||
val := k.MustInt()
|
||||
@ -242,7 +275,7 @@ func (k *Key) InInt(defaultVal int, candidates []int) int {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// In always returns value without error,
|
||||
// InInt64 always returns value without error,
|
||||
// it returns default value if error occurs or doesn't fit into candidates.
|
||||
func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 {
|
||||
val := k.MustInt64()
|
||||
@ -254,6 +287,24 @@ func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 {
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// InTimeFormat always parses with given format and returns value without error,
|
||||
// it returns default value if error occurs or doesn't fit into candidates.
|
||||
func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time {
|
||||
val := k.MustTimeFormat(format)
|
||||
for _, cand := range candidates {
|
||||
if val == cand {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
// InTime always parses with RFC3339 format and returns value without error,
|
||||
// it returns default value if error occurs or doesn't fit into candidates.
|
||||
func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time {
|
||||
return k.InTimeFormat(time.RFC3339, defaultVal, candidates)
|
||||
}
|
||||
|
||||
// Strings returns list of string devide by given delimiter.
|
||||
func (k *Key) Strings(delim string) []string {
|
||||
str := k.String()
|
||||
@ -298,6 +349,21 @@ func (k *Key) Int64s(delim string) []int64 {
|
||||
return vals
|
||||
}
|
||||
|
||||
// TimesFormat parses with given format and returns list of time.Time devide by given delimiter.
|
||||
func (k *Key) TimesFormat(format, delim string) []time.Time {
|
||||
strs := k.Strings(delim)
|
||||
vals := make([]time.Time, len(strs))
|
||||
for i := range strs {
|
||||
vals[i], _ = time.Parse(format, strs[i])
|
||||
}
|
||||
return vals
|
||||
}
|
||||
|
||||
// Times parses with RFC3339 format and returns list of time.Time devide by given delimiter.
|
||||
func (k *Key) Times(delim string) []time.Time {
|
||||
return k.TimesFormat(time.RFC3339, delim)
|
||||
}
|
||||
|
||||
// SetValue changes key value.
|
||||
func (k *Key) SetValue(v string) {
|
||||
k.value = v
|
||||
@ -446,6 +512,8 @@ type File struct {
|
||||
|
||||
// To keep data in order.
|
||||
sectionList []string
|
||||
|
||||
NameMapper
|
||||
}
|
||||
|
||||
// newFile initializes File object with given data sources.
|
||||
@ -803,6 +871,11 @@ func (f *File) SaveTo(filename string) (err error) {
|
||||
if _, err = buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Write nothing if default section is empty.
|
||||
if len(sec.keyList) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for _, kname := range sec.keyList {
|
||||
|
39
Godeps/_workspace/src/gopkg.in/ini.v1/ini_test.go
generated
vendored
39
Godeps/_workspace/src/gopkg.in/ini.v1/ini_test.go
generated
vendored
@ -18,10 +18,17 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Version(t *testing.T) {
|
||||
Convey("Get version", t, func() {
|
||||
So(Version(), ShouldEqual, _VERSION)
|
||||
})
|
||||
}
|
||||
|
||||
const _CONF_DATA = `
|
||||
; Package name
|
||||
NAME = ini
|
||||
@ -57,11 +64,13 @@ STRING = str
|
||||
BOOL = true
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
|
||||
[array]
|
||||
STRINGS = en, zh, de
|
||||
FLOAT64S = 1.1, 2.2, 3.3
|
||||
INTS = 1, 2, 3
|
||||
TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
|
||||
|
||||
[note]
|
||||
|
||||
@ -206,12 +215,19 @@ func Test_Values(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(v4, ShouldEqual, 10)
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
v5, err := sec.Key("TIME").Time()
|
||||
So(err, ShouldBeNil)
|
||||
So(v5.String(), ShouldEqual, t.String())
|
||||
|
||||
Convey("Must get values with type", func() {
|
||||
So(sec.Key("STRING").MustString("404"), ShouldEqual, "str")
|
||||
So(sec.Key("BOOL").MustBool(), ShouldBeTrue)
|
||||
So(sec.Key("FLOAT64").MustFloat64(), ShouldEqual, 1.25)
|
||||
So(sec.Key("INT").MustInt(), ShouldEqual, 10)
|
||||
So(sec.Key("INT").MustInt64(), ShouldEqual, 10)
|
||||
So(sec.Key("TIME").MustTime().String(), ShouldEqual, t.String())
|
||||
|
||||
Convey("Must get values with default value", func() {
|
||||
So(sec.Key("STRING_404").MustString("404"), ShouldEqual, "404")
|
||||
@ -219,6 +235,10 @@ func Test_Values(t *testing.T) {
|
||||
So(sec.Key("FLOAT64_404").MustFloat64(2.5), ShouldEqual, 2.5)
|
||||
So(sec.Key("INT_404").MustInt(15), ShouldEqual, 15)
|
||||
So(sec.Key("INT_404").MustInt64(15), ShouldEqual, 15)
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "2014-01-01T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec.Key("TIME_404").MustTime(t).String(), ShouldEqual, t.String())
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -230,11 +250,18 @@ func Test_Values(t *testing.T) {
|
||||
So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10)
|
||||
So(sec.Key("INT").InInt64(0, []int64{10, 20, 30}), ShouldEqual, 10)
|
||||
|
||||
zt, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
|
||||
So(err, ShouldBeNil)
|
||||
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec.Key("TIME").InTime(zt, []time.Time{t, time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
|
||||
|
||||
Convey("Get value with candidates and default value", func() {
|
||||
So(sec.Key("STRING_404").In("str", []string{"str", "arr", "types"}), ShouldEqual, "str")
|
||||
So(sec.Key("FLOAT64_404").InFloat64(1.25, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
|
||||
So(sec.Key("INT_404").InInt(10, []int{10, 20, 30}), ShouldEqual, 10)
|
||||
So(sec.Key("INT64_404").InInt64(10, []int64{10, 20, 30}), ShouldEqual, 10)
|
||||
So(sec.Key("TIME_404").InTime(t, []time.Time{time.Now(), time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
|
||||
})
|
||||
})
|
||||
|
||||
@ -257,6 +284,13 @@ func Test_Values(t *testing.T) {
|
||||
for i, v := range []int64{1, 2, 3} {
|
||||
So(vals3[i], ShouldEqual, v)
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
vals4 := sec.Key("TIMES").Times(",")
|
||||
for i, v := range []time.Time{t, t, t} {
|
||||
So(vals4[i].String(), ShouldEqual, v.String())
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Get key hash", func() {
|
||||
@ -270,7 +304,7 @@ func Test_Values(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get key strings", func() {
|
||||
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,FLOAT64,INT")
|
||||
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,FLOAT64,INT,TIME")
|
||||
})
|
||||
|
||||
Convey("Delete a key", func() {
|
||||
@ -338,6 +372,9 @@ func Test_File_SaveTo(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
cfg.Section("").Key("NAME").Comment = "Package name"
|
||||
cfg.Section("author").Comment = `Information about package author
|
||||
# Bio can be written in multiple lines.`
|
||||
So(cfg.SaveTo("testdata/conf_out.ini"), ShouldBeNil)
|
||||
})
|
||||
}
|
||||
|
214
Godeps/_workspace/src/gopkg.in/ini.v1/struct.go
generated
vendored
Normal file
214
Godeps/_workspace/src/gopkg.in/ini.v1/struct.go
generated
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// 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 ini
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// NameMapper represents a ini tag name mapper.
|
||||
type NameMapper func(string) string
|
||||
|
||||
// Built-in name getters.
|
||||
var (
|
||||
// AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
|
||||
AllCapsUnderscore NameMapper = func(raw string) string {
|
||||
newstr := make([]rune, 0, 10)
|
||||
for i, chr := range raw {
|
||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||
if i > 0 {
|
||||
newstr = append(newstr, '_')
|
||||
}
|
||||
}
|
||||
newstr = append(newstr, unicode.ToUpper(chr))
|
||||
}
|
||||
return string(newstr)
|
||||
}
|
||||
// TitleUnderscore converts to format title_underscore.
|
||||
TitleUnderscore NameMapper = func(raw string) string {
|
||||
newstr := make([]rune, 0, 10)
|
||||
for i, chr := range raw {
|
||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||
if i > 0 {
|
||||
newstr = append(newstr, '_')
|
||||
}
|
||||
chr -= ('A' - 'a')
|
||||
}
|
||||
newstr = append(newstr, chr)
|
||||
}
|
||||
return string(newstr)
|
||||
}
|
||||
)
|
||||
|
||||
func (s *Section) parseFieldName(raw, actual string) string {
|
||||
if len(actual) > 0 {
|
||||
return actual
|
||||
}
|
||||
if s.f.NameMapper != nil {
|
||||
return s.f.NameMapper(raw)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func parseDelim(actual string) string {
|
||||
if len(actual) > 0 {
|
||||
return actual
|
||||
}
|
||||
return ","
|
||||
}
|
||||
|
||||
var reflectTime = reflect.TypeOf(time.Now()).Kind()
|
||||
|
||||
func setWithProperType(kind reflect.Kind, key *Key, field reflect.Value, delim string) error {
|
||||
switch kind {
|
||||
case reflect.String:
|
||||
field.SetString(key.String())
|
||||
case reflect.Bool:
|
||||
boolVal, err := key.Bool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(boolVal)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intVal, err := key.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetInt(intVal)
|
||||
case reflect.Float64:
|
||||
floatVal, err := key.Float64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(floatVal)
|
||||
case reflectTime:
|
||||
timeVal, err := key.Time()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(timeVal))
|
||||
case reflect.Slice:
|
||||
vals := key.Strings(delim)
|
||||
numVals := len(vals)
|
||||
if numVals == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sliceOf := field.Type().Elem().Kind()
|
||||
|
||||
var times []time.Time
|
||||
if sliceOf == reflectTime {
|
||||
times = key.Times(delim)
|
||||
}
|
||||
|
||||
slice := reflect.MakeSlice(field.Type(), numVals, numVals)
|
||||
for i := 0; i < numVals; i++ {
|
||||
switch sliceOf {
|
||||
case reflectTime:
|
||||
slice.Index(i).Set(reflect.ValueOf(times[i]))
|
||||
default:
|
||||
slice.Index(i).Set(reflect.ValueOf(vals[i]))
|
||||
}
|
||||
}
|
||||
field.Set(slice)
|
||||
default:
|
||||
return fmt.Errorf("unsupported type '%s'", kind)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Section) mapTo(val reflect.Value) error {
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
typ := val.Type()
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := val.Field(i)
|
||||
tpField := typ.Field(i)
|
||||
|
||||
tag := tpField.Tag.Get("ini")
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := s.parseFieldName(tpField.Name, tag)
|
||||
if len(fieldName) == 0 || !field.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
if tpField.Type.Kind() == reflect.Struct {
|
||||
if sec, err := s.f.GetSection(fieldName); err == nil {
|
||||
if err = sec.mapTo(field); err != nil {
|
||||
return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
} else if tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous {
|
||||
field.Set(reflect.New(tpField.Type.Elem()))
|
||||
if sec, err := s.f.GetSection(fieldName); err == nil {
|
||||
if err = sec.mapTo(field); err != nil {
|
||||
return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if key, err := s.GetKey(fieldName); err == nil {
|
||||
if err = setWithProperType(tpField.Type.Kind(), key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
|
||||
return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapTo maps section to given struct.
|
||||
func (s *Section) MapTo(v interface{}) error {
|
||||
typ := reflect.TypeOf(v)
|
||||
val := reflect.ValueOf(v)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
val = val.Elem()
|
||||
} else {
|
||||
return errors.New("cannot map to non-pointer struct")
|
||||
}
|
||||
|
||||
return s.mapTo(val)
|
||||
}
|
||||
|
||||
// MapTo maps file to given struct.
|
||||
func (f *File) MapTo(v interface{}) error {
|
||||
return f.Section("").MapTo(v)
|
||||
}
|
||||
|
||||
// MapTo maps data sources to given struct with name mapper.
|
||||
func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
|
||||
cfg, err := Load(source, others...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.NameMapper = mapper
|
||||
return cfg.MapTo(v)
|
||||
}
|
||||
|
||||
// MapTo maps data sources to given struct.
|
||||
func MapTo(v, source interface{}, others ...interface{}) error {
|
||||
return MapToWithMapper(v, nil, source, others...)
|
||||
}
|
183
Godeps/_workspace/src/gopkg.in/ini.v1/struct_test.go
generated
vendored
Normal file
183
Godeps/_workspace/src/gopkg.in/ini.v1/struct_test.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// 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 ini
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
type testNested struct {
|
||||
Cities []string `delim:"|"`
|
||||
Visits []time.Time
|
||||
Note string
|
||||
Unused int `ini:"-"`
|
||||
}
|
||||
|
||||
type testEmbeded struct {
|
||||
GPA float64
|
||||
}
|
||||
|
||||
type testStruct struct {
|
||||
Name string `ini:"NAME"`
|
||||
Age int
|
||||
Male bool
|
||||
Money float64
|
||||
Born time.Time
|
||||
Others testNested
|
||||
*testEmbeded `ini:"grade"`
|
||||
Unused int `ini:"-"`
|
||||
}
|
||||
|
||||
const _CONF_DATA_STRUCT = `
|
||||
NAME = Unknwon
|
||||
Age = 21
|
||||
Male = true
|
||||
Money = 1.25
|
||||
Born = 1993-10-07T20:17:05Z
|
||||
|
||||
[Others]
|
||||
Cities = HangZhou|Boston
|
||||
Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
|
||||
Note = Hello world!
|
||||
|
||||
[grade]
|
||||
GPA = 2.8
|
||||
`
|
||||
|
||||
type unsupport struct {
|
||||
Byte byte
|
||||
}
|
||||
|
||||
type unsupport2 struct {
|
||||
Others struct {
|
||||
Cities byte
|
||||
}
|
||||
}
|
||||
|
||||
type unsupport3 struct {
|
||||
Cities byte
|
||||
}
|
||||
|
||||
type unsupport4 struct {
|
||||
*unsupport3 `ini:"Others"`
|
||||
}
|
||||
|
||||
type invalidInt struct {
|
||||
Age int
|
||||
}
|
||||
|
||||
type invalidBool struct {
|
||||
Male bool
|
||||
}
|
||||
|
||||
type invalidFloat struct {
|
||||
Money float64
|
||||
}
|
||||
|
||||
type invalidTime struct {
|
||||
Born time.Time
|
||||
}
|
||||
|
||||
type emptySlice struct {
|
||||
Cities []string
|
||||
}
|
||||
|
||||
const _INVALID_DATA_CONF_STRUCT = `
|
||||
Age = age
|
||||
Male = 123
|
||||
Money = money
|
||||
Born = nil
|
||||
Cities =
|
||||
`
|
||||
|
||||
func Test_Struct(t *testing.T) {
|
||||
Convey("Map file to struct", t, func() {
|
||||
ts := new(testStruct)
|
||||
So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
|
||||
|
||||
So(ts.Name, ShouldEqual, "Unknwon")
|
||||
So(ts.Age, ShouldEqual, 21)
|
||||
So(ts.Male, ShouldBeTrue)
|
||||
So(ts.Money, ShouldEqual, 1.25)
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
So(ts.Born.String(), ShouldEqual, t.String())
|
||||
|
||||
So(strings.Join(ts.Others.Cities, ","), ShouldEqual, "HangZhou,Boston")
|
||||
So(ts.Others.Visits[0].String(), ShouldEqual, t.String())
|
||||
So(ts.Others.Note, ShouldEqual, "Hello world!")
|
||||
So(ts.testEmbeded.GPA, ShouldEqual, 2.8)
|
||||
})
|
||||
|
||||
Convey("Map to non-pointer struct", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(cfg.MapTo(testStruct{}), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to unsupported type", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
cfg.NameMapper = func(raw string) string {
|
||||
if raw == "Byte" {
|
||||
return "NAME"
|
||||
}
|
||||
return raw
|
||||
}
|
||||
So(cfg.MapTo(&unsupport{}), ShouldNotBeNil)
|
||||
So(cfg.MapTo(&unsupport2{}), ShouldNotBeNil)
|
||||
So(cfg.MapTo(&unsupport4{}), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map from invalid data source", t, func() {
|
||||
So(MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to wrong types", t, func() {
|
||||
So(MapTo(&invalidInt{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidBool{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidFloat{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidTime{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&emptySlice{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
type testMapper struct {
|
||||
PackageName string
|
||||
}
|
||||
|
||||
func Test_NameGetter(t *testing.T) {
|
||||
Convey("Test name mappers", t, func() {
|
||||
So(MapToWithMapper(&testMapper{}, TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
|
||||
|
||||
cfg, err := Load([]byte("PACKAGE_NAME=ini"))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
cfg.NameMapper = AllCapsUnderscore
|
||||
tg := new(testMapper)
|
||||
So(cfg.MapTo(tg), ShouldBeNil)
|
||||
So(tg.PackageName, ShouldEqual, "ini")
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user