Compare commits
49 Commits
Author | SHA1 | Date |
---|---|---|
Nemo | cbc329f738 | |
Nemo | d986c22c5a | |
Nemo | fddfe4113c | |
Nemo | 2c02026a8f | |
Nemo | 9bb0367232 | |
Nemo | 86e276b81c | |
Nemo | 794f82a4e2 | |
Nemo | a5adba4a5c | |
Nemo | 2461fc5ace | |
Nemo | f1eb4a8c80 | |
Nemo | e1cb3c9054 | |
Nemo | 79b3302227 | |
Nemo | fc6bfdb113 | |
Nemo | 9105240bcb | |
Nemo | 5d5e939a6b | |
Nemo | dc6531ee98 | |
Nemo | 062df76ec9 | |
Nemo | 108543a4b4 | |
Nemo | eb853b5f4c | |
Nemo | 2885606b4a | |
Nemo | bf66a2f6b3 | |
Nemo | 41b8940751 | |
Nemo | 511cd51730 | |
Nemo | b3f3441d2f | |
Nemo | c26443624f | |
Nemo | dfa13e6d10 | |
Nemo | 8b3df3fb17 | |
Nemo | 89d922062a | |
Nemo | 8ec8ab839e | |
Nemo | e625caee29 | |
Nemo | e8403d43e3 | |
Nemo | 6562dd1cf3 | |
Nemo | 986a0bfbc9 | |
Nemo | 6be76ef8d8 | |
Nemo | c2af505e2a | |
Nemo | af8d7d995b | |
Nemo | 85df2cd6f3 | |
Nemo | d58c04274b | |
Nemo | f24d67d914 | |
Nemo | f42f70d156 | |
Nemo | 83f5afc398 | |
Nemo | 03e864b165 | |
Nemo | ac0db7b024 | |
Nemo | 5bba7b9c87 | |
Nemo | 783c0dc956 | |
Nemo | b0fcf5a284 | |
Nemo | 84dadeb1ff | |
Nemo | cc55f45269 | |
Nemo | f14f923c26 |
|
@ -0,0 +1,12 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[regex.txt]
|
||||
insert_final_newline = true
|
|
@ -0,0 +1,7 @@
|
|||
# Generated file for browsers
|
||||
pincode-regex.js linguist-generated
|
||||
# jasmine is vendored for browser tests
|
||||
tests/jasmine-3.5.0/* linguist-vendored
|
||||
# regex.txt is generated (see src/generate.js)
|
||||
regex.txt linguist-generated
|
||||
regexes.txt linguist-generated
|
|
@ -0,0 +1,3 @@
|
|||
ko_fi: captn3m0
|
||||
liberapay: captn3m0
|
||||
github: captn3m0
|
|
@ -0,0 +1,45 @@
|
|||
on: push
|
||||
name: Tests
|
||||
jobs:
|
||||
node:
|
||||
strategy:
|
||||
matrix:
|
||||
node: ["12", "14", "16", "18", "20"]
|
||||
name: Node.js
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{matrix.node}}
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
php:
|
||||
strategy:
|
||||
matrix:
|
||||
# https://www.php.net/supported-versions.php
|
||||
php: ["7.2", "7.3", "7.4", "8.0", "8.1", "8.2"]
|
||||
name: PHP
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{matrix.php}}
|
||||
tools: phpunit, composer
|
||||
- run: composer install --no-interaction
|
||||
- run: ./vendor/bin/phpunit
|
||||
ruby:
|
||||
strategy:
|
||||
matrix:
|
||||
ruby: ["2.6", "2.7", "3.0", "3.1"]
|
||||
name: Ruby
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler-cache: true
|
||||
- run: bundle install
|
||||
- run: bundle exec rake
|
|
@ -1,3 +1,25 @@
|
|||
/vendor/
|
||||
/.bundle/
|
||||
/.yardoc
|
||||
/_yardoc/
|
||||
/coverage/
|
||||
/dist/
|
||||
/doc/
|
||||
/node_modules/
|
||||
composer.lock
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/tmp/
|
||||
/vendor/
|
||||
__pycache__/
|
||||
/composer.lock
|
||||
/package-lock.json
|
||||
# Current best practice is to commit this
|
||||
# https://bundler.io/man/bundle-install.1.html#THE-GEMFILE-LOCK
|
||||
# but we have zero deps, so it doesn't make sense
|
||||
Gemfile.lock
|
||||
*.gem
|
||||
*.csv
|
||||
.pdm.toml
|
||||
__pypackages__/
|
||||
src/pincode.egg-info/
|
||||
.phpunit.*cache
|
||||
*.bak
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
composer.*
|
||||
vendor/
|
||||
tests/
|
||||
phpunit.xml
|
||||
node_modules/
|
||||
src/*.php
|
||||
src/*.rb
|
||||
.travis.yml
|
||||
src/generate.js
|
||||
HACKING.md
|
||||
dist/
|
||||
# This holds the python source
|
||||
src/pincode
|
||||
*.toml
|
||||
Pipfile
|
||||
.editorconfig
|
||||
regexes.txt
|
||||
__pypackages__
|
||||
.github
|
||||
.gitattributes
|
||||
.phpunit*
|
||||
CHANGELOG.md
|
||||
CONTRIBUTING.md
|
||||
CODE_OF_CONDUCT.md
|
||||
Gemfile*
|
||||
Rakefile
|
||||
bin/
|
||||
phpunit.*
|
||||
*.gem
|
||||
*.csv
|
||||
pincode-regex.js
|
||||
pincode-validator.gemspec
|
||||
src/pincode.egg-info/
|
|
@ -1,5 +0,0 @@
|
|||
language: php
|
||||
php:
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '7.4'
|
|
@ -0,0 +1,11 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [UNRELEASED][unreleased]
|
||||
|
||||
## [1.0.5][1.0.5]
|
||||
##
|
||||
|
||||
[1.0.5]: https://github.com/captn3m0/india-pincode-regex/releases/tag/1.0.5
|
|
@ -0,0 +1,74 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at coc@captnemo.in. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -0,0 +1,38 @@
|
|||
# Contribution Guidelines
|
||||
|
||||
## Generating the regex
|
||||
|
||||
1. Download the latest CSV file from <https://data.gov.in/resources/all-india-pincode-directory-till-last-month>.
|
||||
2. Copy all the pincodes to a pincodes.csv file
|
||||
3. Generate all unique pincodes by running `npm run build`
|
||||
|
||||
## Regex Notes
|
||||
|
||||
Note that the regexes are all PCRE compatible, but do not include `/` at the beginning or end. This is for cross-compatibility and ease of use.
|
||||
The two files are:
|
||||
|
||||
- `regex.txt` - This is the regex for validating a pincode. It is a single regex.
|
||||
- `regexes.txt` - It is a list of regexes, one per line. One regex is available per area code (the first digit of the PIN, which goes from 1-8).
|
||||
|
||||
## Generating the browser-version
|
||||
|
||||
1. Make sure development dependencies are installed.
|
||||
2. `npm run browserify`.
|
||||
3. Test it by opening `tests/index.html` in your browser.
|
||||
|
||||
# PHP Release
|
||||
|
||||
1. `git tag v1.2.3`
|
||||
2. `git push --tags`
|
||||
|
||||
## Ruby Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
||||
|
||||
Run `gem build pincode-validator.gemspec` to build the gem, and `tar --to-stdout -xf *.gem data.tar.gz | tar -zt` to validate the list of files inside the gem before publishing it.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Please see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for the code of conduct.
|
|
@ -0,0 +1,4 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
# Specify your gem's dependencies in pincode-validator.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,23 @@
|
|||
# Generating the regex
|
||||
|
||||
1. Download the latest CSV file from <https://data.gov.in/resources/all-india-pincode-directory-till-last-month>.
|
||||
2. Copy all the pincodes to a pincodes.csv file
|
||||
3. Generate all unique pincodes by running `npm run build`
|
||||
|
||||
# Generating the browser-version
|
||||
|
||||
1. Make sure development dependencies are installed.
|
||||
2. `npm run browserify`.
|
||||
3. Test it by opening `tests/index.html` in your browser.
|
||||
|
||||
# PHP Release
|
||||
|
||||
1. `git tag 1.2.3`
|
||||
2. `git push --tags`
|
||||
|
||||
|
||||
## Ruby Development
|
||||
|
||||
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
||||
|
||||
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
@ -0,0 +1,7 @@
|
|||
Copyright 2020 Abhay Rana
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
91
README.md
91
README.md
|
@ -1,14 +1,22 @@
|
|||
# india-pincode-regex ![Packagist Version](https://img.shields.io/packagist/v/captn3m0/pincode?style=plastic)
|
||||
# india-pincode-regex ![Packagist Version](https://img.shields.io/packagist/v/captn3m0/pincode?style=plastic) [![Build Status](https://travis-ci.org/captn3m0/india-pincode-regex.svg?branch=master)](https://travis-ci.org/captn3m0/india-pincode-regex) ![npm](https://img.shields.io/npm/v/pincode-validator?style=plastic) ![GitHub package.json version](https://img.shields.io/github/package-json/v/captn3m0/india-pincode-regex?style=plastic) ![GitHub](https://img.shields.io/github/license/captn3m0/india-pincode-regex?style=plastic)
|
||||
|
||||
Validate a [Postal Index Number][wiki] for India with a regex. The regexes are available in `regex.txt`. There are 2 regexes. The first validates PINs starting from 1-4, and the second validates the ones starting from 5-8. The reason for the split is to keep the regex size small. Currently they are both at 16K each.
|
||||
Validate a [Postal Index Number][wiki] for India with a few regexes and zero false-positives. The regexes are available in `regex.txt`. There is one regex per area code (the first digit of the PIN, which goes from 1-8). Available as a package for Ruby, Python, Node.js, and browsers.
|
||||
|
||||
## Why?
|
||||
|
||||
A simple `\d{6}` approach marks a lot of invalid pincodes as valid. Out of the 900000 possible combinations, only approximately `19000` are valid pincodes in India. A simple example is `111111` which is an invalid pincode, but any simple 6 digit-check will pass it as a valid one.
|
||||
|
||||
## Source
|
||||
|
||||
The source for the data is the ["All India Pincode Directory"](https://data.gov.in/resources/all-india-pincode-directory) dataset on data.gov.in.
|
||||
The source for the data is the ["All India Pincode Directory"](https://data.gov.in/resources/all-india-pincode-directory) dataset on data.gov.in. The last updated date for the dataset is currently 30th May 2019.
|
||||
|
||||
## Usage
|
||||
|
||||
The `regex.txt` file is 32KB in size, so you can easily use it wherever you want, including browsers.
|
||||
The `regex.txt` file is 32KB in size, so you can easily use it wherever you want, including browsers. If you are using any of the packages below, this is already delivered compressed. You can use the regex directly, or via a few helper methods.
|
||||
|
||||
## Supported Language Versions
|
||||
|
||||
This project only supports [supported versions](https://endoflife.date) of various languages.
|
||||
|
||||
### PHP
|
||||
|
||||
|
@ -18,11 +26,84 @@ To use the PHP package:
|
|||
|
||||
```php
|
||||
use PIN\Validator as P;
|
||||
// validates a given pincode
|
||||
// returns boolean
|
||||
P::validate('110011'); // returns true;
|
||||
|
||||
// Searches for all valid pincodes in a given string.
|
||||
// returns array(string)
|
||||
P::search('bangalore 560029'); // returns ["560029"]
|
||||
```
|
||||
|
||||
### Node.js
|
||||
|
||||
The package is available on [`npm`](https://www.npmjs.com/package/pincode-validator).
|
||||
|
||||
To use the package:
|
||||
|
||||
```js
|
||||
const P = require('pincode-validator');
|
||||
P.validate('110011'); // returns true
|
||||
P.search('my pincode is 560029'); // returns ['560029']
|
||||
|
||||
// or directly use the regex in your code
|
||||
P.exactRegex.match('560029')
|
||||
"address with pincode (560029)".matchAll(P.regex)
|
||||
````
|
||||
|
||||
Please see `tests/validate.js` for more examples.
|
||||
|
||||
## Ruby
|
||||
|
||||
Add this line to your application's Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'pincode_validator'
|
||||
```
|
||||
|
||||
And then execute:
|
||||
|
||||
$ bundle
|
||||
|
||||
Or install it yourself as:
|
||||
|
||||
$ gem install pincode_validator
|
||||
|
||||
```ruby
|
||||
require 'pincode_validator'
|
||||
|
||||
Pin::valid?('560029') # returns true
|
||||
Pin::valid?('111111') # returns false
|
||||
|
||||
Pin::search('my pincode is 244713') # returns ['244713']
|
||||
Pin::search('my pincode is 244713 or 560029') # returns ['244713', '560029']
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
||||
To use it in the browser, download the `pincode-regex.js` file and include it in your browser. `Pincode` is available as a Global variable.
|
||||
|
||||
```html
|
||||
<script src="../pincode-regex.js"></script>
|
||||
<script>
|
||||
Pincode.validate("560029"); // returns true
|
||||
</script>
|
||||
```
|
||||
|
||||
You can use githack for directly using this in your code: <https://rawcdn.githack.com/captn3m0/india-pincode-regex/v2.0.0/pincode-regex.js> (Make sure you use the latest version). Please watch the repo to get notified of new releases.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Everyone interacting in the this project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/captn3m0/outliner/blob/master/CODE_OF_CONDUCT.md).
|
||||
|
||||
## Contributing
|
||||
|
||||
- See [`CONTRIBUTING.md`](CONTRIBUTING.md) for some development details and contribution guidelines
|
||||
- Pull requests are welcome for adding libraries in other languages (in the same repo). Python support is WIP, and I'd love to have support for other languages as well.
|
||||
- This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the [MIT License](https://nemo.mit-license.org/). See LICENSE file for details.
|
||||
|
||||
[wiki]: https://en.wikipedia.org/wiki/Postal_Index_Number
|
||||
[wiki]: https://en.wikipedia.org/wiki/Postal_Index_Number
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
require "bundler/gem_tasks"
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
t.pattern = 'tests/*_spec.rb'
|
||||
end
|
||||
|
||||
task :default => :spec
|
|
@ -0,0 +1,14 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require "bundler/setup"
|
||||
require "pincode_validator"
|
||||
|
||||
# You can add fixtures and/or initialization code here to make experimenting
|
||||
# with your gem easier. You can also use a different console, if you like.
|
||||
|
||||
# (If you use this, don't forget to add pry to your Gemfile!)
|
||||
# require "pry"
|
||||
# Pry.start
|
||||
|
||||
require "irb"
|
||||
IRB.start(__FILE__)
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
set -vx
|
||||
|
||||
bundle install
|
||||
|
||||
# Do any other automated setup that you need to do here
|
|
@ -14,8 +14,28 @@
|
|||
"PIN\\": "src/"
|
||||
}
|
||||
},
|
||||
"archive": {
|
||||
"exclude": [
|
||||
"/tests",
|
||||
"/regex.txt",
|
||||
"/.editorconfig",
|
||||
"/phpunit.xml",
|
||||
|
||||
"/.npmignore",
|
||||
"/package.json",
|
||||
"/pincode-regex.js",
|
||||
"/src/generate.js",
|
||||
"/src/index.js",
|
||||
"/pyproject.toml",
|
||||
"/src/pincode/__init__.py",
|
||||
|
||||
"/pincode-validator.gemspec",
|
||||
"/bin",
|
||||
"/src/pincode_validator.rb"
|
||||
]
|
||||
},
|
||||
"require": {},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0"
|
||||
"phpunit/phpunit": "^9.0 || ^8.0 || ^10.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"name": "india-pincode-regex",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
|
||||
"dev": true
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
|
||||
"integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
|
||||
"dev": true
|
||||
},
|
||||
"regexgen": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/regexgen/-/regexgen-1.3.0.tgz",
|
||||
"integrity": "sha1-sCLzjlEgu0b9zTf6y5EWjxXm/no=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jsesc": "^2.3.0",
|
||||
"regenerate": "^1.3.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
package.json
18
package.json
|
@ -1,13 +1,15 @@
|
|||
{
|
||||
"name": "india-pincode-regex",
|
||||
"version": "1.0.0",
|
||||
"name": "pincode-validator",
|
||||
"version": "2.0.0",
|
||||
"description": "A simple regex based validator for PIN codes in India",
|
||||
"main": "index.js",
|
||||
"main": "src/index.js",
|
||||
"directories": {
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "node tests/validate.js",
|
||||
"build": "node src/generate.js <(sort -u pincodes.csv) > regex.txt",
|
||||
"browserify": "browserify --transform brfs --outfile pincode-regex.js -s Pincode src/index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -27,6 +29,10 @@
|
|||
},
|
||||
"homepage": "https://github.com/captn3m0/india-pincode-regex#readme",
|
||||
"devDependencies": {
|
||||
"regexgen": "^1.3.0"
|
||||
}
|
||||
"brfs": "^2.0.2",
|
||||
"browserify": "^17.0.0",
|
||||
"regexgen": "^1.3.0",
|
||||
"jasmine-core": "^5.0.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,4 @@
|
|||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
||||
</phpunit>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,29 @@
|
|||
require_relative 'src/pincode_validator'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "pincode_validator"
|
||||
spec.version = PincodeValidator::VERSION
|
||||
spec.authors = ["Nemo"]
|
||||
spec.email = ["rubygems@captnemo.in"]
|
||||
|
||||
spec.summary = %q{A simple regex based offline validator for PIN codes in India}
|
||||
spec.homepage = "https://github.com/captn3m0/india-pincode-regex"
|
||||
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
||||
|
||||
spec.metadata["homepage_uri"] = spec.homepage
|
||||
spec.metadata["source_code_uri"] = "https://github.com/captn3m0/india-pincode-regex"
|
||||
|
||||
spec.files = [
|
||||
'Gemfile',
|
||||
'LICENSE',
|
||||
'pincode-validator.gemspec',
|
||||
'README.md',
|
||||
'regex.txt',
|
||||
'src/pincode_validator.rb',
|
||||
]
|
||||
|
||||
spec.license = 'MIT'
|
||||
spec.require_paths = ["src"]
|
||||
spec.add_development_dependency 'rake', '~> 13.0'
|
||||
spec.add_development_dependency 'rspec', '~> 3.12'
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
[project]
|
||||
name = "pincode"
|
||||
version = "2.0.0"
|
||||
description = "A simple offline pincode validator for India"
|
||||
authors = [
|
||||
{name = "Nemo", email = "python@captnemo.in"},
|
||||
]
|
||||
dependencies = ["requests"]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
license = {text = "MIT"}
|
||||
keywords = ["pincode", "regex", "offline", "pin", "validator"]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries"
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
homepage = "https://github.com/captn3m0/india-pincode-regex"
|
||||
Repository = "https://github.com/captn3m0/india-pincode-regex"
|
||||
Documentation = "https://github.com/captn3m0/india-pincode-regex/wiki"
|
||||
|
||||
[tool.pdm]
|
||||
includes = ["CHANGELOG.md", "README.md", "regex.txt", "src/pincode"]
|
||||
excludes = [
|
||||
".github/",
|
||||
"src/*.js",
|
||||
"src/*.php",
|
||||
"tests/*.php",
|
||||
"tests/*.js",
|
||||
"tests/*.rb",
|
||||
"tests/*.html",
|
||||
"tests/jasmine*",
|
||||
"vendor/",
|
||||
"composer.",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"node_modules/"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["pdm-pep517"]
|
||||
build-backend = "pdm.pep517.api"
|
File diff suppressed because one or more lines are too long
|
@ -3,19 +3,53 @@
|
|||
namespace PIN;
|
||||
|
||||
class Validator {
|
||||
static $regexes;
|
||||
|
||||
public static function validate(string $pin) {
|
||||
if(!self::$regexes) {
|
||||
self::$regexes = array_filter(file('regex.txt'));
|
||||
}
|
||||
static $regexes;
|
||||
|
||||
foreach (self::$regexes as $regex) {
|
||||
if (preg_match($regex, $pin) === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public static function init() {
|
||||
if(!self::$regexes) {
|
||||
self::$regexes = array_map(function($line) {
|
||||
return '/' . trim($line) . '/';
|
||||
}, array_filter(file('regexes.txt')));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Validate a PIN code
|
||||
* @param string $pin
|
||||
* @return bool
|
||||
*/
|
||||
public static function validate(string $pin) : bool{
|
||||
self::init();
|
||||
|
||||
foreach (self::$regexes as $regex) {
|
||||
if (strlen($pin) === 6 and preg_match($regex, $pin) === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for PIN codes in a string
|
||||
* @param string $address
|
||||
* @return array
|
||||
*/
|
||||
public static function search(string $address){
|
||||
self::init();
|
||||
$results = [];
|
||||
|
||||
foreach (self::$regexes as $regex) {
|
||||
preg_match_all($regex, $address, $matches);
|
||||
|
||||
$results = array_reduce($matches, function($res, $match) {
|
||||
if (isset($match[0]) and in_array($match[0], $res, true) === false){
|
||||
$res[] = $match[0];
|
||||
}
|
||||
return $res;
|
||||
}, $results);
|
||||
}
|
||||
|
||||
return array_values($results);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,23 +9,33 @@ if (!process.argv[2]) {
|
|||
|
||||
const readInterface = readline.createInterface({
|
||||
input: fs.createReadStream(process.argv[2]),
|
||||
console: false
|
||||
console: false,
|
||||
});
|
||||
|
||||
let t1 = new Trie(),
|
||||
t2 = new Trie();
|
||||
regexes = [];
|
||||
|
||||
readInterface.on("line", function(line) {
|
||||
// There are 3 Pincodes that start with 9, but we
|
||||
// ignore those as test offices.
|
||||
for (var i = 0; i < 8; i++) {
|
||||
regexes.push(new Trie());
|
||||
}
|
||||
|
||||
readInterface.on("line", function (line) {
|
||||
if (line.length === 6) {
|
||||
if (['1', '2', '3', '4'].includes(line.charAt(0))) {
|
||||
t1.add(line);
|
||||
} else {
|
||||
t2.add(line)
|
||||
// First character of the PIN
|
||||
let areaCode = parseInt(line.charAt(0), 10);
|
||||
if (areaCode < 9 && areaCode > 0) {
|
||||
let areaCodeIndex = areaCode - 1;
|
||||
regexes[areaCodeIndex].add(line.trim());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
readInterface.on("close", function() {
|
||||
console.log(t1.toRegExp("u"));
|
||||
console.log(t2.toRegExp("u"));
|
||||
});
|
||||
readInterface.on("close", function () {
|
||||
// We maintain two files, one with a single regex using (|) for each segment
|
||||
fs.writeFileSync("regex.txt", "(" + regexes.join('|') + ")");
|
||||
// And another with 8 regexes, one for each area code.
|
||||
// The latter is required for some languages, which have a regex character limit
|
||||
// (Currently PHP)
|
||||
fs.writeFileSync("regexes.txt", regexes.join("\n"));
|
||||
});
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
const readline = require("readline");
|
||||
const fs = require("fs");
|
||||
|
||||
let contents = fs.readFileSync(__dirname + "/../regex.txt", "utf8").trim()
|
||||
const regex = new RegExp(contents, "gm");
|
||||
const exactRegex = new RegExp("^" + contents + "$");
|
||||
|
||||
module.exports = {
|
||||
// Validates an exact 6 digit string as a valid pincode
|
||||
validate: function(pin) {
|
||||
if (exactRegex.test(pin)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// Returns all valid PIN codes for a given address
|
||||
search: function(address) {
|
||||
return Array.from(address.matchAll(regex), (x) => x[0])
|
||||
},
|
||||
regex: regex,
|
||||
exactRegex: exactRegex
|
||||
};
|
|
@ -0,0 +1,24 @@
|
|||
import os
|
||||
import re
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
def get_project_root() -> Path:
|
||||
return Path(__file__).parent.parent.parent
|
||||
|
||||
regex = list()
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
f = open(get_project_root() / 'regex.txt')
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if (len(line) > 10):
|
||||
# Remove the \n at the end
|
||||
regex.append(re.compile('^' + line[1:-2] + '$'))
|
||||
|
||||
class Pincode:
|
||||
@staticmethod
|
||||
def validate(code):
|
||||
for r in regex:
|
||||
if r.match(code) != None:
|
||||
return True
|
||||
return False
|
|
@ -0,0 +1,25 @@
|
|||
module PincodeValidator
|
||||
VERSION = "2.0.0"
|
||||
FILENAME='regex.txt'
|
||||
|
||||
class Error < StandardError; end
|
||||
|
||||
def self.root
|
||||
File.dirname __dir__
|
||||
end
|
||||
|
||||
@@regex ||=
|
||||
Regexp.new(File.read(File.join root, FILENAME).strip)
|
||||
|
||||
@@exactRegex ||=
|
||||
Regexp.new("^#{File.read(File.join root, FILENAME).strip}$")
|
||||
|
||||
def self.valid?(pincode)
|
||||
return true if @@exactRegex.match? pincode
|
||||
false
|
||||
end
|
||||
|
||||
def self.search?(address)
|
||||
address.scan(@@regex).map(&:first).map(&:strip)
|
||||
end
|
||||
end
|
|
@ -4,9 +4,9 @@ use PIN\Validator as P;
|
|||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SimpleTest extends TestCase {
|
||||
const PINS = ['244713', '560029', '560030'];
|
||||
const PINS = ['244713', '560029', '560030', '110011'];
|
||||
|
||||
const INVALID_PINS = ['999999'];
|
||||
const INVALID_PINS = ['999999', '99999', '9999', '999', '99', '9', '111111', '2447131'];
|
||||
|
||||
public function testSamplePins() {
|
||||
foreach(self::PINS as $pin) {
|
||||
|
@ -17,4 +17,11 @@ class SimpleTest extends TestCase {
|
|||
$this->assertFalse(P::validate($pin), "$pin should be invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testSearch() {
|
||||
$this->assertSame(P::search("560029"), ["560029"]);
|
||||
$this->assertSame(P::search("my pincode is 560029"), ["560029"]);
|
||||
$this->assertSame(P::search("560029 244713"), ["244713", "560029"]);
|
||||
$this->assertSame(P::search("address 560038 bangalore"), ["560038"]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
describe("Pincode", function() {
|
||||
it("should validate correct pincodes", function() {
|
||||
expect(Pincode.validate("110011")).toEqual(true);
|
||||
expect(Pincode.validate("244713")).toEqual(true);
|
||||
expect(Pincode.validate("560029")).toEqual(true);
|
||||
expect(Pincode.validate("560030")).toEqual(true);
|
||||
});
|
||||
|
||||
it("should validate incorrect pincodes", function() {
|
||||
// Incorrect
|
||||
expect(Pincode.validate("1100111")).toEqual(false);
|
||||
expect(Pincode.validate("111111")).toEqual(false);
|
||||
expect(Pincode.validate("999999")).toEqual(false);
|
||||
expect(Pincode.validate("99999")).toEqual(false);
|
||||
expect(Pincode.validate("9999")).toEqual(false);
|
||||
expect(Pincode.validate("999")).toEqual(false);
|
||||
expect(Pincode.validate("99")).toEqual(false);
|
||||
expect(Pincode.validate("9")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should support search method", function() {
|
||||
expect(Pincode.search('bangalore 560038 244713')).toEqual(['560038', '244713']);
|
||||
expect(Pincode.search('bangalore 560038')).toEqual(['560038']);
|
||||
expect(Pincode.search('560038 BENGALURU')).toEqual(['560038']);
|
||||
expect(Pincode.search('560038')).toEqual(['560038']);
|
||||
expect(Pincode.search('my pincode is 244713')).toEqual(['244713']);
|
||||
expect(Pincode.search('560029 pin')).toEqual(['560029']);
|
||||
})
|
||||
|
||||
it("should export direct regexes", function() {
|
||||
expect(Pincode.regex instanceof RegExp).toBe(true);
|
||||
expect(Pincode.exactRegex instanceof RegExp).toBe(true);
|
||||
})
|
||||
|
||||
it("should support exact regex matches", function() {
|
||||
expect(Pincode.exactRegex.test('560029')).toBe(true);
|
||||
expect('111111').not.toMatch(Pincode.exactRegex);
|
||||
expect('address is 560029').not.toMatch(Pincode.exactRegex);
|
||||
})
|
||||
|
||||
it("should support inexact regex matches", function() {
|
||||
expect('560029').toMatch(Pincode.regex);
|
||||
expect('address is 560029').toMatch(Pincode.regex);
|
||||
expect('address is 111111').not.toMatch(Pincode.regex)
|
||||
expect('111111').not.toMatch(Pincode.regex)
|
||||
|
||||
})
|
||||
});
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" type="image/png" href="../node_modules/jasmine-core/images/jasmine_favicon.png">
|
||||
<link rel="stylesheet" type="text/css" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
|
||||
|
||||
<script type="text/javascript" src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
|
||||
<script type="text/javascript" src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
|
||||
<script type="text/javascript" src="../node_modules/jasmine-core/lib/jasmine-core/boot0.js"></script>
|
||||
<script type="text/javascript" src="../node_modules/jasmine-core/lib/jasmine-core/boot1.js"></script>
|
||||
<title>Jasmine tests for Pincode Validator</title>
|
||||
|
||||
<script src="../pincode-regex.js"></script>
|
||||
<script src="browser-spec.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
|
||||
|
||||
If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
|
||||
|
||||
The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
|
||||
|
||||
[jasmine-gem]: http://github.com/pivotal/jasmine-gem
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* ## Require & Instantiate
|
||||
*
|
||||
* Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
|
||||
*/
|
||||
window.jasmine = jasmineRequire.core(jasmineRequire);
|
||||
|
||||
/**
|
||||
* Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference.
|
||||
*/
|
||||
jasmineRequire.html(jasmine);
|
||||
|
||||
/**
|
||||
* Create the Jasmine environment. This is used to run all specs in a project.
|
||||
*/
|
||||
var env = jasmine.getEnv();
|
||||
|
||||
/**
|
||||
* ## The Global Interface
|
||||
*
|
||||
* Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
|
||||
*/
|
||||
var jasmineInterface = jasmineRequire.interface(jasmine, env);
|
||||
|
||||
/**
|
||||
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
|
||||
*/
|
||||
extend(window, jasmineInterface);
|
||||
|
||||
/**
|
||||
* ## Runner Parameters
|
||||
*
|
||||
* More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface.
|
||||
*/
|
||||
|
||||
var queryString = new jasmine.QueryString({
|
||||
getWindowLocation: function() { return window.location; }
|
||||
});
|
||||
|
||||
var filterSpecs = !!queryString.getParam("spec");
|
||||
|
||||
var config = {
|
||||
failFast: queryString.getParam("failFast"),
|
||||
oneFailurePerSpec: queryString.getParam("oneFailurePerSpec"),
|
||||
hideDisabled: queryString.getParam("hideDisabled")
|
||||
};
|
||||
|
||||
var random = queryString.getParam("random");
|
||||
|
||||
if (random !== undefined && random !== "") {
|
||||
config.random = random;
|
||||
}
|
||||
|
||||
var seed = queryString.getParam("seed");
|
||||
if (seed) {
|
||||
config.seed = seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Reporters
|
||||
* The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any).
|
||||
*/
|
||||
var htmlReporter = new jasmine.HtmlReporter({
|
||||
env: env,
|
||||
navigateWithNewParam: function(key, value) { return queryString.navigateWithNewParam(key, value); },
|
||||
addToExistingQueryString: function(key, value) { return queryString.fullStringWithNewParam(key, value); },
|
||||
getContainer: function() { return document.body; },
|
||||
createElement: function() { return document.createElement.apply(document, arguments); },
|
||||
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
|
||||
timer: new jasmine.Timer(),
|
||||
filterSpecs: filterSpecs
|
||||
});
|
||||
|
||||
/**
|
||||
* The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
|
||||
*/
|
||||
env.addReporter(jasmineInterface.jsApiReporter);
|
||||
env.addReporter(htmlReporter);
|
||||
|
||||
/**
|
||||
* Filter which specs will be run by matching the start of the full name against the `spec` query param.
|
||||
*/
|
||||
var specFilter = new jasmine.HtmlSpecFilter({
|
||||
filterString: function() { return queryString.getParam("spec"); }
|
||||
});
|
||||
|
||||
config.specFilter = function(spec) {
|
||||
return specFilter.matches(spec.getFullName());
|
||||
};
|
||||
|
||||
env.configure(config);
|
||||
|
||||
/**
|
||||
* Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack.
|
||||
*/
|
||||
window.setTimeout = window.setTimeout;
|
||||
window.setInterval = window.setInterval;
|
||||
window.clearTimeout = window.clearTimeout;
|
||||
window.clearInterval = window.clearInterval;
|
||||
|
||||
/**
|
||||
* ## Execution
|
||||
*
|
||||
* Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded.
|
||||
*/
|
||||
var currentWindowOnload = window.onload;
|
||||
|
||||
window.onload = function() {
|
||||
if (currentWindowOnload) {
|
||||
currentWindowOnload();
|
||||
}
|
||||
htmlReporter.initialize();
|
||||
env.execute();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for readability above.
|
||||
*/
|
||||
function extend(destination, source) {
|
||||
for (var property in source) destination[property] = source[property];
|
||||
return destination;
|
||||
}
|
||||
|
||||
}());
|
|
@ -0,0 +1,817 @@
|
|||
/*
|
||||
Copyright (c) 2008-2019 Pivotal Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
jasmineRequire.html = function(j$) {
|
||||
j$.ResultsNode = jasmineRequire.ResultsNode();
|
||||
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);
|
||||
j$.QueryString = jasmineRequire.QueryString();
|
||||
j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter();
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlReporter = function(j$) {
|
||||
function ResultsStateBuilder() {
|
||||
this.topResults = new j$.ResultsNode({}, '', null);
|
||||
this.currentParent = this.topResults;
|
||||
this.specsExecuted = 0;
|
||||
this.failureCount = 0;
|
||||
this.pendingSpecCount = 0;
|
||||
}
|
||||
|
||||
ResultsStateBuilder.prototype.suiteStarted = function(result) {
|
||||
this.currentParent.addChild(result, 'suite');
|
||||
this.currentParent = this.currentParent.last();
|
||||
};
|
||||
|
||||
ResultsStateBuilder.prototype.suiteDone = function(result) {
|
||||
this.currentParent.updateResult(result);
|
||||
if (this.currentParent !== this.topResults) {
|
||||
this.currentParent = this.currentParent.parent;
|
||||
}
|
||||
|
||||
if (result.status === 'failed') {
|
||||
this.failureCount++;
|
||||
}
|
||||
};
|
||||
|
||||
ResultsStateBuilder.prototype.specStarted = function(result) {};
|
||||
|
||||
ResultsStateBuilder.prototype.specDone = function(result) {
|
||||
this.currentParent.addChild(result, 'spec');
|
||||
|
||||
if (result.status !== 'excluded') {
|
||||
this.specsExecuted++;
|
||||
}
|
||||
|
||||
if (result.status === 'failed') {
|
||||
this.failureCount++;
|
||||
}
|
||||
|
||||
if (result.status == 'pending') {
|
||||
this.pendingSpecCount++;
|
||||
}
|
||||
};
|
||||
|
||||
function HtmlReporter(options) {
|
||||
var config = function() {
|
||||
return (options.env && options.env.configuration()) || {};
|
||||
},
|
||||
getContainer = options.getContainer,
|
||||
createElement = options.createElement,
|
||||
createTextNode = options.createTextNode,
|
||||
navigateWithNewParam = options.navigateWithNewParam || function() {},
|
||||
addToExistingQueryString =
|
||||
options.addToExistingQueryString || defaultQueryString,
|
||||
filterSpecs = options.filterSpecs,
|
||||
htmlReporterMain,
|
||||
symbols,
|
||||
deprecationWarnings = [];
|
||||
|
||||
this.initialize = function() {
|
||||
clearPrior();
|
||||
htmlReporterMain = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine_html-reporter' },
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-banner' },
|
||||
createDom('a', {
|
||||
className: 'jasmine-title',
|
||||
href: 'http://jasmine.github.io/',
|
||||
target: '_blank'
|
||||
}),
|
||||
createDom('span', { className: 'jasmine-version' }, j$.version)
|
||||
),
|
||||
createDom('ul', { className: 'jasmine-symbol-summary' }),
|
||||
createDom('div', { className: 'jasmine-alert' }),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-results' },
|
||||
createDom('div', { className: 'jasmine-failures' })
|
||||
)
|
||||
);
|
||||
getContainer().appendChild(htmlReporterMain);
|
||||
};
|
||||
|
||||
var totalSpecsDefined;
|
||||
this.jasmineStarted = function(options) {
|
||||
totalSpecsDefined = options.totalSpecsDefined || 0;
|
||||
};
|
||||
|
||||
var summary = createDom('div', { className: 'jasmine-summary' });
|
||||
|
||||
var stateBuilder = new ResultsStateBuilder();
|
||||
|
||||
this.suiteStarted = function(result) {
|
||||
stateBuilder.suiteStarted(result);
|
||||
};
|
||||
|
||||
this.suiteDone = function(result) {
|
||||
stateBuilder.suiteDone(result);
|
||||
|
||||
if (result.status === 'failed') {
|
||||
failures.push(failureDom(result));
|
||||
}
|
||||
addDeprecationWarnings(result);
|
||||
};
|
||||
|
||||
this.specStarted = function(result) {
|
||||
stateBuilder.specStarted(result);
|
||||
};
|
||||
|
||||
var failures = [];
|
||||
this.specDone = function(result) {
|
||||
stateBuilder.specDone(result);
|
||||
|
||||
if (noExpectations(result)) {
|
||||
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
|
||||
if (result.status === 'failed') {
|
||||
console.error(noSpecMsg);
|
||||
} else {
|
||||
console.warn(noSpecMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!symbols) {
|
||||
symbols = find('.jasmine-symbol-summary');
|
||||
}
|
||||
|
||||
symbols.appendChild(
|
||||
createDom('li', {
|
||||
className: this.displaySpecInCorrectFormat(result),
|
||||
id: 'spec_' + result.id,
|
||||
title: result.fullName
|
||||
})
|
||||
);
|
||||
|
||||
if (result.status === 'failed') {
|
||||
failures.push(failureDom(result));
|
||||
}
|
||||
|
||||
addDeprecationWarnings(result);
|
||||
};
|
||||
|
||||
this.displaySpecInCorrectFormat = function(result) {
|
||||
return noExpectations(result) && result.status === 'passed'
|
||||
? 'jasmine-empty'
|
||||
: this.resultStatus(result.status);
|
||||
};
|
||||
|
||||
this.resultStatus = function(status) {
|
||||
if (status === 'excluded') {
|
||||
return config().hideDisabled
|
||||
? 'jasmine-excluded-no-display'
|
||||
: 'jasmine-excluded';
|
||||
}
|
||||
return 'jasmine-' + status;
|
||||
};
|
||||
|
||||
this.jasmineDone = function(doneResult) {
|
||||
var banner = find('.jasmine-banner');
|
||||
var alert = find('.jasmine-alert');
|
||||
var order = doneResult && doneResult.order;
|
||||
var i;
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-duration' },
|
||||
'finished in ' + doneResult.totalTime / 1000 + 's'
|
||||
)
|
||||
);
|
||||
|
||||
banner.appendChild(optionsMenu(config()));
|
||||
|
||||
if (stateBuilder.specsExecuted < totalSpecsDefined) {
|
||||
var skippedMessage =
|
||||
'Ran ' +
|
||||
stateBuilder.specsExecuted +
|
||||
' of ' +
|
||||
totalSpecsDefined +
|
||||
' specs - run all';
|
||||
var skippedLink = addToExistingQueryString('spec', '');
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-bar jasmine-skipped' },
|
||||
createDom(
|
||||
'a',
|
||||
{ href: skippedLink, title: 'Run all specs' },
|
||||
skippedMessage
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
var statusBarMessage = '';
|
||||
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
|
||||
var globalFailures = (doneResult && doneResult.failedExpectations) || [];
|
||||
var failed = stateBuilder.failureCount + globalFailures.length > 0;
|
||||
|
||||
if (totalSpecsDefined > 0 || failed) {
|
||||
statusBarMessage +=
|
||||
pluralize('spec', stateBuilder.specsExecuted) +
|
||||
', ' +
|
||||
pluralize('failure', stateBuilder.failureCount);
|
||||
if (stateBuilder.pendingSpecCount) {
|
||||
statusBarMessage +=
|
||||
', ' + pluralize('pending spec', stateBuilder.pendingSpecCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (doneResult.overallStatus === 'passed') {
|
||||
statusBarClassName += ' jasmine-passed ';
|
||||
} else if (doneResult.overallStatus === 'incomplete') {
|
||||
statusBarClassName += ' jasmine-incomplete ';
|
||||
statusBarMessage =
|
||||
'Incomplete: ' +
|
||||
doneResult.incompleteReason +
|
||||
', ' +
|
||||
statusBarMessage;
|
||||
} else {
|
||||
statusBarClassName += ' jasmine-failed ';
|
||||
}
|
||||
|
||||
var seedBar;
|
||||
if (order && order.random) {
|
||||
seedBar = createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-seed-bar' },
|
||||
', randomized with seed ',
|
||||
createDom(
|
||||
'a',
|
||||
{
|
||||
title: 'randomized with seed ' + order.seed,
|
||||
href: seedHref(order.seed)
|
||||
},
|
||||
order.seed
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: statusBarClassName },
|
||||
statusBarMessage,
|
||||
seedBar
|
||||
)
|
||||
);
|
||||
|
||||
var errorBarClassName = 'jasmine-bar jasmine-errored';
|
||||
var afterAllMessagePrefix = 'AfterAll ';
|
||||
|
||||
for (i = 0; i < globalFailures.length; i++) {
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: errorBarClassName },
|
||||
globalFailureMessage(globalFailures[i])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function globalFailureMessage(failure) {
|
||||
if (failure.globalErrorType === 'load') {
|
||||
var prefix = 'Error during loading: ' + failure.message;
|
||||
|
||||
if (failure.filename) {
|
||||
return (
|
||||
prefix + ' in ' + failure.filename + ' line ' + failure.lineno
|
||||
);
|
||||
} else {
|
||||
return prefix;
|
||||
}
|
||||
} else {
|
||||
return afterAllMessagePrefix + failure.message;
|
||||
}
|
||||
}
|
||||
|
||||
addDeprecationWarnings(doneResult);
|
||||
|
||||
var warningBarClassName = 'jasmine-bar jasmine-warning';
|
||||
for (i = 0; i < deprecationWarnings.length; i++) {
|
||||
var warning = deprecationWarnings[i];
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: warningBarClassName },
|
||||
'DEPRECATION: ' + warning
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
var results = find('.jasmine-results');
|
||||
results.appendChild(summary);
|
||||
|
||||
summaryList(stateBuilder.topResults, summary);
|
||||
|
||||
if (failures.length) {
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
|
||||
createDom('span', {}, 'Spec List | '),
|
||||
createDom(
|
||||
'a',
|
||||
{ className: 'jasmine-failures-menu', href: '#' },
|
||||
'Failures'
|
||||
)
|
||||
)
|
||||
);
|
||||
alert.appendChild(
|
||||
createDom(
|
||||
'span',
|
||||
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
|
||||
createDom(
|
||||
'a',
|
||||
{ className: 'jasmine-spec-list-menu', href: '#' },
|
||||
'Spec List'
|
||||
),
|
||||
createDom('span', {}, ' | Failures ')
|
||||
)
|
||||
);
|
||||
|
||||
find('.jasmine-failures-menu').onclick = function() {
|
||||
setMenuModeTo('jasmine-failure-list');
|
||||
};
|
||||
find('.jasmine-spec-list-menu').onclick = function() {
|
||||
setMenuModeTo('jasmine-spec-list');
|
||||
};
|
||||
|
||||
setMenuModeTo('jasmine-failure-list');
|
||||
|
||||
var failureNode = find('.jasmine-failures');
|
||||
for (i = 0; i < failures.length; i++) {
|
||||
failureNode.appendChild(failures[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function failureDom(result) {
|
||||
var failure = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-spec-detail jasmine-failed' },
|
||||
failureDescription(result, stateBuilder.currentParent),
|
||||
createDom('div', { className: 'jasmine-messages' })
|
||||
);
|
||||
var messages = failure.childNodes[1];
|
||||
|
||||
for (var i = 0; i < result.failedExpectations.length; i++) {
|
||||
var expectation = result.failedExpectations[i];
|
||||
messages.appendChild(
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-result-message' },
|
||||
expectation.message
|
||||
)
|
||||
);
|
||||
messages.appendChild(
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-stack-trace' },
|
||||
expectation.stack
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (result.failedExpectations.length === 0) {
|
||||
messages.appendChild(
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-result-message' },
|
||||
'Spec has no expectations'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return failure;
|
||||
}
|
||||
|
||||
function summaryList(resultsTree, domParent) {
|
||||
var specListNode;
|
||||
for (var i = 0; i < resultsTree.children.length; i++) {
|
||||
var resultNode = resultsTree.children[i];
|
||||
if (filterSpecs && !hasActiveSpec(resultNode)) {
|
||||
continue;
|
||||
}
|
||||
if (resultNode.type === 'suite') {
|
||||
var suiteListNode = createDom(
|
||||
'ul',
|
||||
{ className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
|
||||
createDom(
|
||||
'li',
|
||||
{
|
||||
className:
|
||||
'jasmine-suite-detail jasmine-' + resultNode.result.status
|
||||
},
|
||||
createDom(
|
||||
'a',
|
||||
{ href: specHref(resultNode.result) },
|
||||
resultNode.result.description
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
summaryList(resultNode, suiteListNode);
|
||||
domParent.appendChild(suiteListNode);
|
||||
}
|
||||
if (resultNode.type === 'spec') {
|
||||
if (domParent.getAttribute('class') !== 'jasmine-specs') {
|
||||
specListNode = createDom('ul', { className: 'jasmine-specs' });
|
||||
domParent.appendChild(specListNode);
|
||||
}
|
||||
var specDescription = resultNode.result.description;
|
||||
if (noExpectations(resultNode.result)) {
|
||||
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
|
||||
}
|
||||
if (
|
||||
resultNode.result.status === 'pending' &&
|
||||
resultNode.result.pendingReason !== ''
|
||||
) {
|
||||
specDescription =
|
||||
specDescription +
|
||||
' PENDING WITH MESSAGE: ' +
|
||||
resultNode.result.pendingReason;
|
||||
}
|
||||
specListNode.appendChild(
|
||||
createDom(
|
||||
'li',
|
||||
{
|
||||
className: 'jasmine-' + resultNode.result.status,
|
||||
id: 'spec-' + resultNode.result.id
|
||||
},
|
||||
createDom(
|
||||
'a',
|
||||
{ href: specHref(resultNode.result) },
|
||||
specDescription
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function optionsMenu(config) {
|
||||
var optionsMenuDom = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-run-options' },
|
||||
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-payload' },
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-stop-on-failure' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-fail-fast',
|
||||
id: 'jasmine-fail-fast',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-fail-fast' },
|
||||
'stop execution on spec failure'
|
||||
)
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-throw-failures' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-throw',
|
||||
id: 'jasmine-throw-failures',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-throw-failures' },
|
||||
'stop spec on expectation failure'
|
||||
)
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-random-order' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-random',
|
||||
id: 'jasmine-random-order',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-random-order' },
|
||||
'run tests in random order'
|
||||
)
|
||||
),
|
||||
createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-hide-disabled' },
|
||||
createDom('input', {
|
||||
className: 'jasmine-disabled',
|
||||
id: 'jasmine-hide-disabled',
|
||||
type: 'checkbox'
|
||||
}),
|
||||
createDom(
|
||||
'label',
|
||||
{ className: 'jasmine-label', for: 'jasmine-hide-disabled' },
|
||||
'hide disabled tests'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
|
||||
failFastCheckbox.checked = config.failFast;
|
||||
failFastCheckbox.onclick = function() {
|
||||
navigateWithNewParam('failFast', !config.failFast);
|
||||
};
|
||||
|
||||
var throwCheckbox = optionsMenuDom.querySelector(
|
||||
'#jasmine-throw-failures'
|
||||
);
|
||||
throwCheckbox.checked = config.oneFailurePerSpec;
|
||||
throwCheckbox.onclick = function() {
|
||||
navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
|
||||
};
|
||||
|
||||
var randomCheckbox = optionsMenuDom.querySelector(
|
||||
'#jasmine-random-order'
|
||||
);
|
||||
randomCheckbox.checked = config.random;
|
||||
randomCheckbox.onclick = function() {
|
||||
navigateWithNewParam('random', !config.random);
|
||||
};
|
||||
|
||||
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
|
||||
hideDisabled.checked = config.hideDisabled;
|
||||
hideDisabled.onclick = function() {
|
||||
navigateWithNewParam('hideDisabled', !config.hideDisabled);
|
||||
};
|
||||
|
||||
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger'),
|
||||
optionsPayload = optionsMenuDom.querySelector('.jasmine-payload'),
|
||||
isOpen = /\bjasmine-open\b/;
|
||||
|
||||
optionsTrigger.onclick = function() {
|
||||
if (isOpen.test(optionsPayload.className)) {
|
||||
optionsPayload.className = optionsPayload.className.replace(
|
||||
isOpen,
|
||||
''
|
||||
);
|
||||
} else {
|
||||
optionsPayload.className += ' jasmine-open';
|
||||
}
|
||||
};
|
||||
|
||||
return optionsMenuDom;
|
||||
}
|
||||
|
||||
function failureDescription(result, suite) {
|
||||
var wrapper = createDom(
|
||||
'div',
|
||||
{ className: 'jasmine-description' },
|
||||
createDom(
|
||||
'a',
|
||||
{ title: result.description, href: specHref(result) },
|
||||
result.description
|
||||
)
|
||||
);
|
||||
var suiteLink;
|
||||
|
||||
while (suite && suite.parent) {
|
||||
wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
|
||||
suiteLink = createDom(
|
||||
'a',
|
||||
{ href: suiteHref(suite) },
|
||||
suite.result.description
|
||||
);
|
||||
wrapper.insertBefore(suiteLink, wrapper.firstChild);
|
||||
|
||||
suite = suite.parent;
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function suiteHref(suite) {
|
||||
var els = [];
|
||||
|
||||
while (suite && suite.parent) {
|
||||
els.unshift(suite.result.description);
|
||||
suite = suite.parent;
|
||||
}
|
||||
|
||||
return addToExistingQueryString('spec', els.join(' '));
|
||||
}
|
||||
|
||||
function addDeprecationWarnings(result) {
|
||||
if (result && result.deprecationWarnings) {
|
||||
for (var i = 0; i < result.deprecationWarnings.length; i++) {
|
||||
var warning = result.deprecationWarnings[i].message;
|
||||
if (!j$.util.arrayContains(warning)) {
|
||||
deprecationWarnings.push(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function find(selector) {
|
||||
return getContainer().querySelector('.jasmine_html-reporter ' + selector);
|
||||
}
|
||||
|
||||
function clearPrior() {
|
||||
// return the reporter
|
||||
var oldReporter = find('');
|
||||
|
||||
if (oldReporter) {
|
||||
getContainer().removeChild(oldReporter);
|
||||
}
|
||||
}
|
||||
|
||||
function createDom(type, attrs, childrenVarArgs) {
|
||||
var el = createElement(type);
|
||||
|
||||
for (var i = 2; i < arguments.length; i++) {
|
||||
var child = arguments[i];
|
||||
|
||||
if (typeof child === 'string') {
|
||||
el.appendChild(createTextNode(child));
|
||||
} else {
|
||||
if (child) {
|
||||
el.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var attr in attrs) {
|
||||
if (attr == 'className') {
|
||||
el[attr] = attrs[attr];
|
||||
} else {
|
||||
el.setAttribute(attr, attrs[attr]);
|
||||
}
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function pluralize(singular, count) {
|
||||
var word = count == 1 ? singular : singular + 's';
|
||||
|
||||
return '' + count + ' ' + word;
|
||||
}
|
||||
|
||||
function specHref(result) {
|
||||
return addToExistingQueryString('spec', result.fullName);
|
||||
}
|
||||
|
||||
function seedHref(seed) {
|
||||
return addToExistingQueryString('seed', seed);
|
||||
}
|
||||
|
||||
function defaultQueryString(key, value) {
|
||||
return '?' + key + '=' + value;
|
||||
}
|
||||
|
||||
function setMenuModeTo(mode) {
|
||||
htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
|
||||
}
|
||||
|
||||
function noExpectations(result) {
|
||||
var allExpectations =
|
||||
result.failedExpectations.length + result.passedExpectations.length;
|
||||
|
||||
return (
|
||||
allExpectations === 0 &&
|
||||
(result.status === 'passed' || result.status === 'failed')
|
||||
);
|
||||
}
|
||||
|
||||
function hasActiveSpec(resultNode) {
|
||||
if (resultNode.type == 'spec' && resultNode.result.status != 'excluded') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (resultNode.type == 'suite') {
|
||||
for (var i = 0, j = resultNode.children.length; i < j; i++) {
|
||||
if (hasActiveSpec(resultNode.children[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HtmlReporter;
|
||||
};
|
||||
|
||||
jasmineRequire.HtmlSpecFilter = function() {
|
||||
function HtmlSpecFilter(options) {
|
||||
var filterString =
|
||||
options &&
|
||||
options.filterString() &&
|
||||
options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
||||
var filterPattern = new RegExp(filterString);
|
||||
|
||||
this.matches = function(specName) {
|
||||
return filterPattern.test(specName);
|
||||
};
|
||||
}
|
||||
|
||||
return HtmlSpecFilter;
|
||||
};
|
||||
|
||||
jasmineRequire.ResultsNode = function() {
|
||||
function ResultsNode(result, type, parent) {
|
||||
this.result = result;
|
||||
this.type = type;
|
||||
this.parent = parent;
|
||||
|
||||
this.children = [];
|
||||
|
||||
this.addChild = function(result, type) {
|
||||
this.children.push(new ResultsNode(result, type, this));
|
||||
};
|
||||
|
||||
this.last = function() {
|
||||
return this.children[this.children.length - 1];
|
||||
};
|
||||
|
||||
this.updateResult = function(result) {
|
||||
this.result = result;
|
||||
};
|
||||
}
|
||||
|
||||
return ResultsNode;
|
||||
};
|
||||
|
||||
jasmineRequire.QueryString = function() {
|
||||
function QueryString(options) {
|
||||
this.navigateWithNewParam = function(key, value) {
|
||||
options.getWindowLocation().search = this.fullStringWithNewParam(
|
||||
key,
|
||||
value
|
||||
);
|
||||
};
|
||||
|
||||
this.fullStringWithNewParam = function(key, value) {
|
||||
var paramMap = queryStringToParamMap();
|
||||
paramMap[key] = value;
|
||||
return toQueryString(paramMap);
|
||||
};
|
||||
|
||||
this.getParam = function(key) {
|
||||
return queryStringToParamMap()[key];
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
function toQueryString(paramMap) {
|
||||
var qStrPairs = [];
|
||||
for (var prop in paramMap) {
|
||||
qStrPairs.push(
|
||||
encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])
|
||||
);
|
||||
}
|
||||
return '?' + qStrPairs.join('&');
|
||||
}
|
||||
|
||||
function queryStringToParamMap() {
|
||||
var paramStr = options.getWindowLocation().search.substring(1),
|
||||
params = [],
|
||||
paramMap = {};
|
||||
|
||||
if (paramStr.length > 0) {
|
||||
params = paramStr.split('&');
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var p = params[i].split('=');
|
||||
var value = decodeURIComponent(p[1]);
|
||||
if (value === 'true' || value === 'false') {
|
||||
value = JSON.parse(value);
|
||||
}
|
||||
paramMap[decodeURIComponent(p[0])] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return paramMap;
|
||||
}
|
||||
}
|
||||
|
||||
return QueryString;
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,12 @@
|
|||
from pincode import Pincode
|
||||
from nose.tools import assert_equals
|
||||
|
||||
def test_valid_pincodes():
|
||||
VALID_PINS = ['244713', '560029', '560030', '110011']
|
||||
for pin in VALID_PINS:
|
||||
assert_equals(True, Pincode.validate(pin), pin + " should be valid")
|
||||
|
||||
def test_invalid_pincodes():
|
||||
INVALID_PINS = ['999999', '99999', '9999', '999', '99', '9', '111111', '2447131'];
|
||||
for pin in INVALID_PINS:
|
||||
assert_equals(False, Pincode.validate(pin), pin + " should be invalid")
|
|
@ -0,0 +1,43 @@
|
|||
const P = require('../src/index');
|
||||
const assert = require('assert');
|
||||
|
||||
// A few correct ones
|
||||
assert.strictEqual(P.validate('110011'), true, '110011');
|
||||
assert.strictEqual(P.validate('244713'), true, '244713');
|
||||
assert.strictEqual(P.validate('560029'), true, '560029');
|
||||
assert.strictEqual(P.validate('560030'), true, '560030');
|
||||
|
||||
// Incorrect
|
||||
assert.strictEqual(P.validate('address 560030'), false, 'address 560030 should fail');
|
||||
assert.strictEqual(P.validate('1100111'), false, '1100111');
|
||||
assert.strictEqual(P.validate('111111'), false, '111111');
|
||||
assert.strictEqual(P.validate('999999'), false, '999999');
|
||||
assert.strictEqual(P.validate('99999'), false, '99999');
|
||||
assert.strictEqual(P.validate('9999'), false, '9999');
|
||||
assert.strictEqual(P.validate('999'), false, '999');
|
||||
assert.strictEqual(P.validate('99'), false, '99');
|
||||
assert.strictEqual(P.validate('9'), false, '9');
|
||||
|
||||
// Validate search method
|
||||
assert.deepEqual(P.search('bangalore 560038 244713'), ['560038', '244713'])
|
||||
assert.deepEqual(P.search('bangalore 560038'), ['560038'])
|
||||
assert.deepEqual(P.search('560038 BENGALURU'), ['560038'])
|
||||
assert.deepEqual(P.search('560038'), ['560038'])
|
||||
assert.deepEqual(P.search('my pincode is 244713'), ['244713'])
|
||||
assert.deepEqual(P.search('560029 pin'), ['560029'])
|
||||
|
||||
// Validate direct regex exports
|
||||
assert(P.regex instanceof RegExp)
|
||||
assert(P.exactRegex instanceof RegExp)
|
||||
|
||||
// exact regex only works with 6 digit strings
|
||||
assert(P.exactRegex.test('560029'))
|
||||
assert.match('560029', P.exactRegex)
|
||||
assert.doesNotMatch('111111', P.exactRegex)
|
||||
assert.doesNotMatch('address is 560029', P.exactRegex)
|
||||
|
||||
// Normal regex works with long addresses
|
||||
assert.match('560029', P.regex)
|
||||
assert.match('address is 560029', P.regex)
|
||||
assert.doesNotMatch('address is 111111', P.regex)
|
||||
assert.doesNotMatch('111111', P.regex)
|
|
@ -0,0 +1,23 @@
|
|||
require 'pincode_validator'
|
||||
|
||||
describe PincodeValidator do
|
||||
it 'should validate pincodes' do
|
||||
['244713', '560029', '560030', '110011'].each do |pin|
|
||||
expect(described_class::valid? pin).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should validate incorrect pincodes' do
|
||||
['999999', '99999', '9999', '999', '99', '9', '111111', '2447131'].each do |pin|
|
||||
expect(described_class::valid? pin).to eq(false), "#{pin} should be invalid"
|
||||
end
|
||||
end
|
||||
|
||||
it 'should search pincodes' do
|
||||
expect(described_class::search? '560029').to eq(['560029'])
|
||||
expect(described_class::search? '560029, 560030').to eq(['560029', '560030'])
|
||||
expect(described_class::search? '560029, 560030, 110011').to eq(['560029', '560030', '110011'])
|
||||
expect(described_class::search? 'bangalore 560029').to eq(['560029'])
|
||||
expect(described_class::search? 'bangalore 1').to eq([])
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue