diff options
| -rw-r--r-- | .document | 4 | ||||
| -rw-r--r-- | .github/CODEOWNERS | 1 | ||||
| -rw-r--r-- | .github/dependabot.yml | 6 | ||||
| -rw-r--r-- | .github/release.yml | 4 | ||||
| -rw-r--r-- | .github/workflows/push_gem.yml | 46 | ||||
| -rw-r--r-- | .github/workflows/sync-ruby.yml | 33 | ||||
| -rw-r--r-- | .github/workflows/test.yml | 34 | ||||
| -rw-r--r-- | .gitignore | 9 | ||||
| -rw-r--r-- | CHANGELOG.md | 85 | ||||
| -rw-r--r-- | Gemfile | 8 | ||||
| -rw-r--r-- | Rakefile | 10 | ||||
| -rw-r--r-- | debian/changelog | 12 | ||||
| -rw-r--r-- | debian/control | 11 | ||||
| -rw-r--r-- | debian/copyright | 2 | ||||
| -rw-r--r-- | debian/upstream/metadata | 4 | ||||
| -rw-r--r-- | debian/watch | 11 | ||||
| -rw-r--r-- | ipaddr.gemspec | 53 | ||||
| -rw-r--r-- | lib/ipaddr.rb | 30 | ||||
| -rw-r--r-- | test/lib/helper.rb | 4 | ||||
| -rw-r--r-- | test/test_ipaddr.rb | 670 |
20 files changed, 987 insertions, 50 deletions
diff --git a/.document b/.document new file mode 100644 index 0000000..419e2c2 --- /dev/null +++ b/.document @@ -0,0 +1,4 @@ +CHANGELOG.md +LICENSE.txt +README.md +lib/ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0236f71 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @knu diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b18fd29 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'weekly' diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..db1d8e9 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,4 @@ +changelog: + exclude: + labels: + - dependencies # Added by Dependabot diff --git a/.github/workflows/push_gem.yml b/.github/workflows/push_gem.yml new file mode 100644 index 0000000..8b4bfe1 --- /dev/null +++ b/.github/workflows/push_gem.yml @@ -0,0 +1,46 @@ +name: Publish gem to rubygems.org + +on: + push: + tags: + - 'v*' + +permissions: + contents: read + +jobs: + push: + if: github.repository == 'ruby/ipaddr' + runs-on: ubuntu-latest + + environment: + name: rubygems.org + url: https://rubygems.org/gems/ipaddr + + permissions: + contents: write + id-token: write + + steps: + - name: Harden Runner + uses: step-security/harden-runner@6c3c2f2c1c457b00c10c4848d6f5491db3b629df # v2.18.0 + with: + egress-policy: audit + + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5.0.1 + + - name: Set up Ruby + uses: ruby/setup-ruby@d5126b9b3579e429dd52e51e68624dda2e05be25 # v1.267.0 + with: + bundler-cache: true + ruby-version: ruby + + - name: Publish to RubyGems + uses: rubygems/release-gem@6317d8d1f7e28c24d28f6eff169ea854948bd9f7 # v1.2.0 + + - name: Create GitHub release + run: | + tag_name="$(git describe --tags --abbrev=0)" + gh release create "${tag_name}" --verify-tag --generate-notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sync-ruby.yml b/.github/workflows/sync-ruby.yml new file mode 100644 index 0000000..f5df56c --- /dev/null +++ b/.github/workflows/sync-ruby.yml @@ -0,0 +1,33 @@ +name: Sync ruby +on: + push: + branches: [master] +jobs: + sync: + name: Sync ruby + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'ruby' }} + steps: + - uses: actions/checkout@v6 + + - name: Create GitHub App token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: 2060836 + private-key: ${{ secrets.RUBY_SYNC_DEFAULT_GEMS_PRIVATE_KEY }} + owner: ruby + repositories: ruby + + - name: Sync to ruby/ruby + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: ruby + repo: ruby + workflow_file_name: sync_default_gems.yml + github_token: ${{ steps.app-token.outputs.token }} + ref: master + client_payload: | + {"gem":"${{ github.event.repository.name }}","before":"${{ github.event.before }}","after":"${{ github.event.after }}"} + propagate_failure: true + wait_interval: 10 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..6e1088a --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: build + +on: [push, pull_request] + +jobs: + ruby-versions: + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + min_version: 2.4 + + build: + needs: ruby-versions + name: build (${{ matrix.ruby }} / ${{ matrix.os }}) + strategy: + matrix: + ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} + os: [ ubuntu-latest, macos-latest ] + exclude: + - { os: macos-latest, ruby: '2.4' } + - { os: macos-latest, ruby: '2.5' } + include: + - { os: macos-15-intel, ruby: '2.4' } + - { os: macos-15-intel, ruby: '2.5' } + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v6 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # 'bundle install' and cache + - name: Run test + run: bundle exec rake test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0cb6eeb --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ffb6493 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,85 @@ +1.2.9 +----- + +- Fix IPAddr#== returning true when compared with nil for 0.0.0.0 and :: [\#76](https://github.com/ruby/ipaddr/pull/76) ([taketo1113](https://github.com/taketo1113)) +- Fix IPAddr#private?, #link_local? and #loopback? incorrectly matching public IPv6 addresses as IPv4-mapped [\#106](https://github.com/ruby/ipaddr/pull/106) ([jarthod](https://github.com/jarthod)) +- Follow-up fix for InvalidAddressError messages [\#92](https://github.com/ruby/ipaddr/pull/92) ([taketo1113](https://github.com/taketo1113)) + +1.2.8 +----- + +- Fix InvalidAddressError message [\#70](https://github.com/ruby/ipaddr/pull/70) ([ishikawa999](https://github.com/ishikawa999)) +- Remove warning by asserting its presence [\#87](https://github.com/ruby/ipaddr/pull/87) ([etiennebarrie](https://github.com/etiennebarrie)) +- Fix #ipv4_compat returning invalid prefix [\#86](https://github.com/ruby/ipaddr/pull/86) ([taketo1113](https://github.com/taketo1113)) +- Add IPAddr#+/- [\#71](https://github.com/ruby/ipaddr/pull/71) ([taketo1113](https://github.com/taketo1113)) +- Drop support for Ruby 2.3 [\#79](https://github.com/ruby/ipaddr/pull/79) ([taketo1113](https://github.com/taketo1113)) + +1.2.7 +----- + +- Add `IPAddr#to_json/as_json` [\#77](https://github.com/ruby/ipaddr/pull/77) ([taketo1113](https://github.com/taketo1113)) +- Consider IPv4-mapped IPv6 addresses link local/loopback if IPV4 address is private [\#65](https://github.com/ruby/ipaddr/pull/65) ([Earlopain](https://github.com/Earlopain)) +- Fix broken exception messages [\#64](https://github.com/ruby/ipaddr/pull/64) ([lrandall-godaddy](https://github.com/lrandall-godaddy)) +- ntop: Measure address size in bytes [\#61](https://github.com/ruby/ipaddr/pull/61) ([hanazuki](https://github.com/hanazuki)) +- String\#split seems to be faster than capturing digits with Regexp [\#50](https://github.com/ruby/ipaddr/pull/50) ([amatsuda](https://github.com/amatsuda)) +- Prefer String\#start\_with? over Regexp.match [\#49](https://github.com/ruby/ipaddr/pull/49) ([amatsuda](https://github.com/amatsuda)) +- Add IPAddr\#wildcard\_mask [\#44](https://github.com/ruby/ipaddr/pull/44) ([taketo1113](https://github.com/taketo1113)) +- Add IPAddr.cidr to return ip address in cidr notation [\#23](https://github.com/ruby/ipaddr/pull/23) ([beanieboi](https://github.com/beanieboi)) + +1.2.6 +----- + +- Consider IPv4-mapped IPv6 addresses private if IPv4 address is private [\#57](https://github.com/ruby/ipaddr/pull/57) ([jeremyevans](https://github.com/jeremyevans)) +- Improve performance of include? by 5-10x [\#47](https://github.com/ruby/ipaddr/pull/47) ([skipkayhil](https://github.com/skipkayhil)) + +1.2.5 +----- + +- No user-visible changes for gem users + +1.2.4 +----- + +- Fix exception calling `to_range' after `freeze' - fix \#35 [\#36](https://github.com/ruby/ipaddr/pull/36) ([esparta](https://github.com/esparta)) +- IPAddr\#native must also coerce `@mask_addr` [\#34](https://github.com/ruby/ipaddr/pull/34) ([casperisfine](https://github.com/casperisfine)) +- Expose IPAddr::VERSION [\#33](https://github.com/ruby/ipaddr/pull/33) ([casperisfine](https://github.com/casperisfine)) + +1.2.3 +----- + +- Ruby 2.3 is the minimum supported version +- Follow the license change in Ruby and add BSD-2-Clause +- Make the parser a bit stricter [Bug #15832](https://bugs.ruby-lang.org/issues/15832) + - Disallow leading zeros and extra slashes in mask +- Make IPAddr#include? consider range of argument [Bug #14119](https://bugs.ruby-lang.org/issues/14119) +- Support zone identifiers in IPv6 addresses [Feature #10911](https://bugs.ruby-lang.org/issues/10911) +- Fix include? and ipv4_mapped (https://github.com/ruby/ipaddr/pull/31) + +1.2.2 +----- + +- Include the input in the message when raising InvalidAddressError [Feature #5987] (https://bugs.ruby-lang.org/issues/5987) + +1.2.1 +----- + +- Enable frozen_string_literal and do a bit of code cleanup + +1.2.0 +----- + +- Add `IPAddr#link_local?` [Feature #10912](https://bugs.ruby-lang.org/issues/10912) +- Add `IPAddr#private?` [Feature #11666](https://bugs.ruby-lang.org/issues/11666) +- Add `IPAddr#loopback?` +- IPAddr.new now rejects invalid address mask. [Bug #13399] +- Warn that `IPAddr#ipv4_compat` and `#ipv4_compat?` are deprecated [Bug #13769] + +1.1.0 +----- + +- Add IPAddr#prefix + +1.0.0 +----- + +- Initial release as gem extracted from ruby 2.4.1. @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +gemspec + +gem "bundler" +gem "rake" +gem "test-unit" +gem "test-unit-ruby-core" diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..5d512c8 --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require "bundler/gem_tasks" +require "rake/testtask" + +Rake::TestTask.new(:test) do |t| + t.libs << "test/lib" + t.ruby_opts << "-rhelper" + t.test_files = FileList["test/**/test_*.rb"] +end + +task :default => :test diff --git a/debian/changelog b/debian/changelog index 5ea29a2..20d728b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +ruby-ipaddr (1.2.9-1) unstable; urgency=medium + + * Team upload. + * Upgrade the watch file to version 5. + * New upstream release. + * Refresh the upstream metadata. + * Refresh the copyright file. + * Update Standards-Version to 4.7.4. + * Drop Rules-Requires-Root field, it is now redundant. + + -- Simon Quigley <tsimonq2@debian.org> Wed, 29 Apr 2026 10:47:15 -0500 + ruby-ipaddr (1.2.8-1) unstable; urgency=medium * Team upload. diff --git a/debian/control b/debian/control index 0ba4e17..822b126 100644 --- a/debian/control +++ b/debian/control @@ -1,23 +1,18 @@ Source: ruby-ipaddr Section: ruby -Priority: optional Maintainer: Debian Ruby Team <pkg-ruby-extras-maintainers@lists.alioth.debian.org> Uploaders: Vinay Keshava <vinaykeshava@disroot.org> -Build-Depends: debhelper-compat (= 13), - gem2deb (>= 2.1~) -Standards-Version: 4.7.3 +Build-Depends: debhelper-compat (= 13), gem2deb (>= 2.1~) +Standards-Version: 4.7.4 Vcs-Git: https://salsa.debian.org/ruby-team/ruby-ipaddr.git Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-ipaddr Homepage: https://github.com/ruby/ipaddr Testsuite: autopkgtest-pkg-ruby -Rules-Requires-Root: no Package: ruby-ipaddr Architecture: all Multi-Arch: foreign -Depends: ${misc:Depends}, - ${ruby:Depends}, - ${shlibs:Depends} +Depends: ${misc:Depends}, ${ruby:Depends}, ${shlibs:Depends} Description: class to manipulate an IP address in ruby IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and IPv6 are supported. diff --git a/debian/copyright b/debian/copyright index 372ff00..78b774d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -10,6 +10,8 @@ License: Expat Files: debian/* Copyright: 2022 Vinay Keshava <vinaykeshava@disroot.org> + 2023 Pirate Praveen <praveen@debian.org> + 2025-2026 Simon Quigley <tsimonq2@debian.org> License: Expat Comment: The Debian packaging is licensed under the same terms as the source. diff --git a/debian/upstream/metadata b/debian/upstream/metadata index 2e5d2a7..a326294 100644 --- a/debian/upstream/metadata +++ b/debian/upstream/metadata @@ -1,7 +1,7 @@ --- -Archive: GitHub (FIXME) +Archive: GitHub Bug-Database: https://github.com/ruby/ipaddr/issues Bug-Submit: https://github.com/ruby/ipaddr/issues/new -Changelog: https://github.com/ruby/ipaddr/releases +Changelog: https://github.com/ruby/ipaddr/blob/master/CHANGELOG.md Repository: https://github.com/ruby/ipaddr.git Repository-Browse: https://github.com/ruby/ipaddr diff --git a/debian/watch b/debian/watch index 93bd76c..cd64e15 100644 --- a/debian/watch +++ b/debian/watch @@ -1,7 +1,4 @@ -version=4 -https://gemwatch.debian.net/ipaddr .*/ipaddr-(.*).tar.gz - -# Use the regex below for github-based sources -# opts=uversionmangle=s/[_.+-]?(rc|pre|dev|beta|alpha|b|a)/~$1/i,\ -# filenamemangle=s%(?:.+/)?v?@ANY_VERSION@(@ARCHIVE_EXT@)%@PACKAGE@-$1$2% \ -# https://github.com/<owner>/<repo>/tags .*/v?@ANY_VERSION@@ARCHIVE_EXT@ +Version: 5 +Template: GitHub +Owner: ruby +Project: ipaddr diff --git a/ipaddr.gemspec b/ipaddr.gemspec index 821c142..cabc916 100644 --- a/ipaddr.gemspec +++ b/ipaddr.gemspec @@ -1,23 +1,36 @@ -######################################################### -# This file has been automatically generated by gem2tgz # -######################################################### -# -*- encoding: utf-8 -*- -# stub: ipaddr 1.2.8 ruby lib +# frozen_string_literal: true +# coding: utf-8 -Gem::Specification.new do |s| - s.name = "ipaddr".freeze - s.version = "1.2.8".freeze +if File.exist?(File.expand_path("ipaddr.gemspec")) + lib = File.expand_path("../lib", __FILE__) + $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) - s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= - s.require_paths = ["lib".freeze] - s.authors = ["Akinori MUSHA".freeze, "Hajimu UMEMOTO".freeze] - s.date = "1980-01-02" - s.description = "IPAddr provides a set of methods to manipulate an IP address.\nBoth IPv4 and IPv6 are supported.\n".freeze - s.email = ["knu@idaemons.org".freeze, "ume@mahoroba.org".freeze] - s.files = ["LICENSE.txt".freeze, "README.md".freeze, "lib/ipaddr.rb".freeze] - s.homepage = "https://github.com/ruby/ipaddr".freeze - s.licenses = ["Ruby".freeze, "BSD-2-Clause".freeze] - s.required_ruby_version = Gem::Requirement.new(">= 2.4".freeze) - s.rubygems_version = "3.6.9".freeze - s.summary = "A class to manipulate an IP address in ruby".freeze + file = File.expand_path("ipaddr.rb", lib) +else + # for ruby-core + file = File.expand_path("../ipaddr.rb", __FILE__) +end + +version = File.foreach(file).find do |line| + /^\s*VERSION\s*=\s*["'](.*)["']/ =~ line and break $1 +end + +Gem::Specification.new do |spec| + spec.name = "ipaddr" + spec.version = version + spec.authors = ["Akinori MUSHA", "Hajimu UMEMOTO"] + spec.email = ["knu@idaemons.org", "ume@mahoroba.org"] + + spec.summary = %q{A class to manipulate an IP address in ruby} + spec.description = <<-'DESCRIPTION' +IPAddr provides a set of methods to manipulate an IP address. +Both IPv4 and IPv6 are supported. + DESCRIPTION + spec.homepage = "https://github.com/ruby/ipaddr" + spec.licenses = ["Ruby", "BSD-2-Clause"] + + spec.files = ["LICENSE.txt", "README.md", "lib/ipaddr.rb"] + spec.require_paths = ["lib"] + + spec.required_ruby_version = ">= 2.4" end diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 725ff30..70b804f 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -41,7 +41,7 @@ require 'socket' class IPAddr # The version string - VERSION = "1.2.8" + VERSION = "1.2.9" # 32 bit mask for IPv4 IN4MASK = 0xffffffff @@ -164,6 +164,10 @@ class IPAddr # Returns true if two ipaddrs are equal. def ==(other) + if other.nil? + return false + end + other = coerce_other(other) rescue false @@ -293,7 +297,7 @@ class IPAddr @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8 when Socket::AF_INET6 @addr == 1 || # ::1 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8 )) else @@ -314,10 +318,10 @@ class IPAddr @addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16 when Socket::AF_INET6 @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 || - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8 - @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12 - @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16 + @addr & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12 + @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16 )) else raise AddressFamilyError, "unsupported address family" @@ -335,7 +339,7 @@ class IPAddr @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16 when Socket::AF_INET6 @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16 )) else @@ -368,7 +372,7 @@ class IPAddr # into an IPv4-mapped IPv6 address. def ipv4_mapped if !ipv4? - raise InvalidAddressError, "not an IPv4 address: #{@addr}" + raise InvalidAddressError, "not an IPv4 address: #{to_s}" end clone = self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6) clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000) @@ -380,7 +384,7 @@ class IPAddr def ipv4_compat warn "IPAddr\##{__callee__} is obsolete", uplevel: 1 if $VERBOSE if !ipv4? - raise InvalidAddressError, "not an IPv4 address: #{@addr}" + raise InvalidAddressError, "not an IPv4 address: #{to_s}" end clone = self.clone.set(@addr, Socket::AF_INET6) clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000) @@ -413,7 +417,7 @@ class IPAddr # Returns a string for DNS reverse lookup compatible with RFC3172. def ip6_arpa if !ipv6? - raise InvalidAddressError, "not an IPv6 address: #{@addr}" + raise InvalidAddressError, "not an IPv6 address: #{to_s}" end return _reverse + ".ip6.arpa" end @@ -421,7 +425,7 @@ class IPAddr # Returns a string for DNS reverse lookup compatible with RFC1886. def ip6_int if !ipv6? - raise InvalidAddressError, "not an IPv6 address: #{@addr}" + raise InvalidAddressError, "not an IPv6 address: #{to_s}" end return _reverse + ".ip6.int" end @@ -743,19 +747,19 @@ class IPAddr right = '' when RE_IPV6ADDRLIKE_COMPRESSED if $4 - left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{@addr}" + left.count(':') <= 6 or raise InvalidAddressError, "invalid address: #{left}" addr = in_addr($~[4,4]) left = $1 right = $3 + '0:0' else left.count(':') <= ($1.empty? || $2.empty? ? 8 : 7) or - raise InvalidAddressError, "invalid address: #{@addr}" + raise InvalidAddressError, "invalid address: #{left}" left = $1 right = $2 addr = 0 end else - raise InvalidAddressError, "invalid address: #{@addr}" + raise InvalidAddressError, "invalid address: #{left}" end l = left.split(':') r = right.split(':') diff --git a/test/lib/helper.rb b/test/lib/helper.rb new file mode 100644 index 0000000..bef8234 --- /dev/null +++ b/test/lib/helper.rb @@ -0,0 +1,4 @@ +require "test/unit" +require "core_assertions" + +Test::Unit::TestCase.include Test::Unit::CoreAssertions diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb new file mode 100644 index 0000000..9725ab3 --- /dev/null +++ b/test/test_ipaddr.rb @@ -0,0 +1,670 @@ +# frozen_string_literal: true +require 'test/unit' +require 'ipaddr' + +class TC_IPAddr < Test::Unit::TestCase + def test_s_new + [ + ["3FFE:505:ffff::/48"], + ["0:0:0:1::"], + ["2001:200:300::/48"], + ["2001:200:300::192.168.1.2/48"], + ["1:2:3:4:5:6:7::"], + ["::2:3:4:5:6:7:8"], + ].each { |args| + assert_nothing_raised { + IPAddr.new(*args) + } + } + + a = IPAddr.new + assert_equal("::", a.to_s) + assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string) + assert_equal("::/128", a.cidr) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(128, a.prefix) + + a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678") + assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s) + assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string) + assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678/128", a.cidr) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(128, a.prefix) + + a = IPAddr.new("3ffe:505:2::/48") + assert_equal("3ffe:505:2::", a.to_s) + assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string) + assert_equal("3ffe:505:2::/48", a.cidr) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(false, a.ipv4?) + assert_equal(true, a.ipv6?) + assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect) + assert_equal(48, a.prefix) + + a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::") + assert_equal("3ffe:505:2::", a.to_s) + assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string) + assert_equal("3ffe:505:2::/48", a.cidr) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(48, a.prefix) + assert_nil(a.zone_id) + + a = IPAddr.new("fe80::1%ab0") + assert_equal("fe80::1%ab0", a.to_s) + assert_equal("fe80:0000:0000:0000:0000:0000:0000:0001%ab0", a.to_string) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(false, a.ipv4?) + assert_equal(true, a.ipv6?) + assert_equal("#<IPAddr: IPv6:fe80:0000:0000:0000:0000:0000:0000:0001%ab0/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>", a.inspect) + assert_equal(128, a.prefix) + assert_equal('%ab0', a.zone_id) + + a = IPAddr.new("0.0.0.0") + assert_equal("0.0.0.0", a.to_s) + assert_equal("0.0.0.0", a.to_string) + assert_equal("0.0.0.0/32", a.cidr) + assert_equal(Socket::AF_INET, a.family) + assert_equal(32, a.prefix) + + a = IPAddr.new("192.168.1.2") + assert_equal("192.168.1.2", a.to_s) + assert_equal("192.168.1.2", a.to_string) + assert_equal("192.168.1.2/32", a.cidr) + assert_equal(Socket::AF_INET, a.family) + assert_equal(true, a.ipv4?) + assert_equal(false, a.ipv6?) + assert_equal(32, a.prefix) + + a = IPAddr.new("192.168.1.2/26") + assert_equal("192.168.1.0", a.to_s) + assert_equal("192.168.1.0", a.to_string) + assert_equal("192.168.1.0/26", a.cidr) + assert_equal(Socket::AF_INET, a.family) + assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.192>", a.inspect) + assert_equal(26, a.prefix) + + a = IPAddr.new("192.168.1.2/255.255.255.0") + assert_equal("192.168.1.0", a.to_s) + assert_equal("192.168.1.0", a.to_string) + assert_equal("192.168.1.0/24", a.cidr) + assert_equal(Socket::AF_INET, a.family) + assert_equal(24, a.prefix) + + (0..32).each do |prefix| + assert_equal(prefix, IPAddr.new("10.20.30.40/#{prefix}").prefix) + end + (0..128).each do |prefix| + assert_equal(prefix, IPAddr.new("1:2:3:4:5:6:7:8/#{prefix}").prefix) + end + + assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s) + assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s) + + assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s) + assert_equal("1:2:3:4:5:6:7:0", IPAddr.new("1:2:3:4:5:6:7::").to_s) + assert_equal("0:2:3:4:5:6:7:8", IPAddr.new("::2:3:4:5:6:7:8").to_s) + + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.256") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.011") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%]") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("[192.168.1.2]/120") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("[2001:200:300::]\nINVALID") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.1/32\nINVALID") } + assert_raise(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.1/32/20") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("192.168.0.1/032") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("::1/0128") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("::1/255.255.255.0") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("::1/129") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("192.168.0.1/33") } + assert_raise(IPAddr::InvalidPrefixError) { IPAddr.new("192.168.0.1/255.255.255.1") } + assert_raise(IPAddr::AddressFamilyError) { IPAddr.new(1) } + assert_raise(IPAddr::AddressFamilyError) { IPAddr.new("::ffff:192.168.1.2/120", Socket::AF_INET) } + end + + def test_s_new_ntoh + addr = '' + IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c| + addr += sprintf("%02x", c) + } + assert_equal("123456789abcdef0123456789abcdef0", addr) + addr = '' + IPAddr.new("123.45.67.89").hton.each_byte { |c| + addr += sprintf("%02x", c) + } + assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr) + a = IPAddr.new("3ffe:505:2::") + assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s) + a = IPAddr.new("192.168.2.1") + assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s) + end + + def test_ntop + # IPv4 + assert_equal("192.168.1.1", IPAddr.ntop("\xC0\xA8\x01\x01".b)) + assert_equal("10.231.140.171", IPAddr.ntop("\x0A\xE7\x8C\xAB".b)) + # IPv6 + assert_equal("0000:0000:0000:0000:0000:0000:0000:0001", + IPAddr.ntop("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".b)) + assert_equal("fe80:0000:0000:0000:f09f:9985:f09f:9986", + IPAddr.ntop("\xFE\x80\x00\x00\x00\x00\x00\x00\xF0\x9F\x99\x85\xF0\x9F\x99\x86".b)) + + # Invalid parameters + ## wrong length + assert_raise(IPAddr::AddressFamilyError) { + IPAddr.ntop("192.168.1.1".b) + } + assert_raise(IPAddr::AddressFamilyError) { + IPAddr.ntop("\xC0\xA8\x01\xFF1".b) + } + ## UTF-8 + assert_raise(IPAddr::InvalidAddressError) { + IPAddr.ntop("192.168.1.1") + } + assert_raise(IPAddr::InvalidAddressError) { + IPAddr.ntop("\x0A\x0A\x0A\x0A") + } + assert_raise(IPAddr::InvalidAddressError) { + IPAddr.ntop("\x0A\xE7\x8C\xAB") + } + assert_raise(IPAddr::InvalidAddressError) { + IPAddr.ntop("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01") + } + assert_raise(IPAddr::InvalidAddressError) { + IPAddr.ntop("\xFE\x80\x00\x00\x00\x00\x00\x00\xF0\x9F\x99\x85\xF0\x9F\x99\x86") + } + end + + def test_ipv4_compat + a = IPAddr.new("::192.168.1.2") + assert_equal("::192.168.1.2", a.to_s) + assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string) + assert_equal(Socket::AF_INET6, a.family) + assert_warning(/obsolete/) { + assert_predicate(a, :ipv4_compat?) + } + b = a.native + assert_equal("192.168.1.2", b.to_s) + assert_equal(Socket::AF_INET, b.family) + assert_warning(/obsolete/) { + assert_not_predicate(b, :ipv4_compat?) + } + + a = IPAddr.new("192.168.1.2") + assert_warning(/obsolete/) { + b = a.ipv4_compat + } + assert_equal("::192.168.1.2", b.to_s) + assert_equal(Socket::AF_INET6, b.family) + assert_equal(128, b.prefix) + + a = IPAddr.new("192.168.0.0/16") + assert_warning(/obsolete/) { + b = a.ipv4_compat + } + assert_equal("::192.168.0.0", b.to_s) + assert_equal(Socket::AF_INET6, b.family) + assert_equal(112, b.prefix) + end + + def test_ipv4_compat_with_error_message + e = assert_raise(IPAddr::InvalidAddressError) do + assert_warning(/obsolete/) { + IPAddr.new('2001:db8::').ipv4_compat + } + end + assert_equal('not an IPv4 address: 2001:db8::', e.message) + end + + def test_ipv4_mapped + a = IPAddr.new("::ffff:192.168.1.2") + assert_equal("::ffff:192.168.1.2", a.to_s) + assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string) + assert_equal(Socket::AF_INET6, a.family) + assert_equal(true, a.ipv4_mapped?) + b = a.native + assert_equal("192.168.1.2", b.to_s) + assert_equal(Socket::AF_INET, b.family) + assert_equal(false, b.ipv4_mapped?) + + a = IPAddr.new("192.168.1.2") + b = a.ipv4_mapped + assert_equal("::ffff:192.168.1.2", b.to_s) + assert_equal(Socket::AF_INET6, b.family) + end + + def test_ipv4_mapped_with_error_message + e = assert_raise(IPAddr::InvalidAddressError) do + IPAddr.new('2001:db8::').ipv4_mapped + end + assert_equal('not an IPv4 address: 2001:db8::', e.message) + end + + def test_reverse + assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse) + assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse) + end + + def test_ip6_arpa + assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa) + e = assert_raise(IPAddr::InvalidAddressError) { + IPAddr.new("192.168.2.1").ip6_arpa + } + assert_equal('not an IPv6 address: 192.168.2.1', e.message) + end + + def test_ip6_int + assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int) + e = assert_raise(IPAddr::InvalidAddressError) { + IPAddr.new("192.168.2.1").ip6_int + } + assert_equal('not an IPv6 address: 192.168.2.1', e.message) + end + + def test_prefix_writer + a = IPAddr.new("192.168.1.2") + ["1", "255.255.255.0", "ffff:ffff:ffff:ffff::", nil, 1.0, -1, 33].each { |x| + assert_raise(IPAddr::InvalidPrefixError) { a.prefix = x } + } + a = IPAddr.new("1:2:3:4:5:6:7:8") + ["1", "255.255.255.0", "ffff:ffff:ffff:ffff::", nil, 1.0, -1, 129].each { |x| + assert_raise(IPAddr::InvalidPrefixError) { a.prefix = x } + } + + a = IPAddr.new("192.168.1.2") + a.prefix = 26 + assert_equal(26, a.prefix) + assert_equal("192.168.1.0", a.to_s) + + a = IPAddr.new("1:2:3:4:5:6:7:8") + a.prefix = 52 + assert_equal(52, a.prefix) + assert_equal("1:2:3::", a.to_s) + end + + def test_to_s + assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string) + assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s) + end + + def test_as_json + assert_equal("192.168.1.2", IPAddr.new("192.168.1.2").as_json) + assert_equal("192.168.1.0/24", IPAddr.new("192.168.1.2/24").as_json) + assert_equal("2001:200:300::1", IPAddr.new("2001:200:300::1").as_json) + assert_equal("2001:200:300::/48", IPAddr.new("2001:200:300::/48").as_json) + end + + def test_to_json + assert_equal("\"192.168.1.2\"", IPAddr.new("192.168.1.2").to_json) + assert_equal("\"192.168.1.0/24\"", IPAddr.new("192.168.1.2/24").to_json) + assert_equal("\"2001:200:300::1\"", IPAddr.new("2001:200:300::1").to_json) + assert_equal("\"2001:200:300::/48\"", IPAddr.new("2001:200:300::/48").to_json) + end + + def test_netmask + a = IPAddr.new("192.168.1.2/8") + assert_equal(a.netmask, "255.0.0.0") + + a = IPAddr.new("192.168.1.2/16") + assert_equal(a.netmask, "255.255.0.0") + + a = IPAddr.new("192.168.1.2/24") + assert_equal(a.netmask, "255.255.255.0") + end + + def test_wildcard_mask + a = IPAddr.new("192.168.1.2/1") + assert_equal(a.wildcard_mask, "127.255.255.255") + + a = IPAddr.new("192.168.1.2/8") + assert_equal(a.wildcard_mask, "0.255.255.255") + + a = IPAddr.new("192.168.1.2/16") + assert_equal(a.wildcard_mask, "0.0.255.255") + + a = IPAddr.new("192.168.1.2/24") + assert_equal(a.wildcard_mask, "0.0.0.255") + + a = IPAddr.new("192.168.1.2/32") + assert_equal(a.wildcard_mask, "0.0.0.0") + + a = IPAddr.new("3ffe:505:2::/48") + assert_equal(a.wildcard_mask, "0000:0000:0000:ffff:ffff:ffff:ffff:ffff") + + a = IPAddr.new("3ffe:505:2::/128") + assert_equal(a.wildcard_mask, "0000:0000:0000:0000:0000:0000:0000:0000") + end + + def test_zone_id + a = IPAddr.new("192.168.1.2") + assert_raise(IPAddr::InvalidAddressError) { a.zone_id = '%ab0' } + assert_raise(IPAddr::InvalidAddressError) { a.zone_id } + + a = IPAddr.new("1:2:3:4:5:6:7:8") + a.zone_id = '%ab0' + assert_equal('%ab0', a.zone_id) + assert_equal("1:2:3:4:5:6:7:8%ab0", a.to_s) + assert_raise(IPAddr::InvalidAddressError) { a.zone_id = '%' } + end + + def test_to_range + a1 = IPAddr.new("127.0.0.1") + range = a1..a1 + assert_equal(range, a1.to_range) + assert_equal(range, a1.freeze.to_range) + + a2 = IPAddr.new("192.168.0.1/16") + range = IPAddr.new("192.168.0.0")..IPAddr.new("192.168.255.255") + assert_equal(range, a2.to_range) + assert_equal(range, a2.freeze.to_range) + + a3 = IPAddr.new("3ffe:505:2::1") + range = a3..a3 + assert_equal(range, a3.to_range) + assert_equal(range, a3.freeze.to_range) + + a4 = IPAddr.new("::ffff/127") + range = IPAddr.new("::fffe")..IPAddr.new("::ffff") + assert_equal(range, a4.to_range) + assert_equal(range, a4.freeze.to_range) + end +end + +class TC_Operator < Test::Unit::TestCase + + IN6MASK32 = "ffff:ffff::" + IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + + def setup + @in6_addr_any = IPAddr.new() + @a = IPAddr.new("3ffe:505:2::/48") + @b = IPAddr.new("0:0:0:1::") + @c = IPAddr.new(IN6MASK32) + @inconvertible_range = 1..5 + @inconvertible_string = "sometext" + end + alias set_up setup + + def test_or + assert_equal("3ffe:505:2:1::", (@a | @b).to_s) + a = @a + a |= @b + assert_equal("3ffe:505:2:1::", a.to_s) + assert_equal("3ffe:505:2::", @a.to_s) + assert_equal("3ffe:505:2:1::", + (@a | 0x00000000000000010000000000000000).to_s) + end + + def test_and + assert_equal("3ffe:505::", (@a & @c).to_s) + a = @a + a &= @c + assert_equal("3ffe:505::", a.to_s) + assert_equal("3ffe:505:2::", @a.to_s) + assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s) + end + + def test_shift_right + assert_equal("0:3ffe:505:2::", (@a >> 16).to_s) + a = @a + a >>= 16 + assert_equal("0:3ffe:505:2::", a.to_s) + assert_equal("3ffe:505:2::", @a.to_s) + end + + def test_shift_left + assert_equal("505:2::", (@a << 16).to_s) + a = @a + a <<= 16 + assert_equal("505:2::", a.to_s) + assert_equal("3ffe:505:2::", @a.to_s) + end + + def test_carrot + a = ~@in6_addr_any + assert_equal(IN6MASK128, a.to_s) + assert_equal("::", @in6_addr_any.to_s) + end + + def test_plus + a = IPAddr.new("192.168.1.10") + assert_equal("192.168.1.20", (a + 10).to_s) + + a = IPAddr.new("0.0.0.0") + assert_equal("0.0.0.10", (a + 10).to_s) + + a = IPAddr.new("255.255.255.255") + assert_raise(IPAddr::InvalidAddressError) { a + 10 } + + a = IPAddr.new("3ffe:505:2::a") + assert_equal("3ffe:505:2::14", (a + 10).to_s) + + a = IPAddr.new("::") + assert_equal("::a", (a + 10).to_s) + + a = IPAddr.new("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") + assert_raise(IPAddr::InvalidAddressError) { a + 10 } + end + + def test_minus + a = IPAddr.new("192.168.1.10") + assert_equal("192.168.1.0", (a - 10).to_s) + + a = IPAddr.new("0.0.0.0") + assert_raise(IPAddr::InvalidAddressError) { a - 10 } + + a = IPAddr.new("255.255.255.255") + assert_equal("255.255.255.245", (a - 10).to_s) + + a = IPAddr.new("3ffe:505:2::a") + assert_equal("3ffe:505:2::", (a - 10).to_s) + + a = IPAddr.new("::") + assert_raise(IPAddr::InvalidAddressError) { a - 10 } + + a = IPAddr.new("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") + assert_equal("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff5", (a - 10).to_s) + end + + def test_equal + assert_equal(true, @a == IPAddr.new("3FFE:505:2::")) + assert_equal(true, @a == IPAddr.new("3ffe:0505:0002::")) + assert_equal(true, @a == IPAddr.new("3ffe:0505:0002:0:0:0:0:0")) + assert_equal(false, @a == IPAddr.new("3ffe:505:3::")) + assert_equal(true, @a != IPAddr.new("3ffe:505:3::")) + assert_equal(false, @a != IPAddr.new("3ffe:505:2::")) + assert_equal(false, @a == @inconvertible_range) + assert_equal(false, @a == @inconvertible_string) + assert_equal(false, IPAddr.new("0.0.0.0") == nil) + assert_equal(false, IPAddr.new("::") == nil) + end + + def test_compare + assert_equal(nil, @a <=> @inconvertible_range) + assert_equal(nil, @a <=> @inconvertible_string) + end + + def test_mask + a = @a.mask(32) + assert_equal("3ffe:505::", a.to_s) + assert_equal("3ffe:505::", @a.mask("ffff:ffff::").to_s) + assert_equal("3ffe:505:2::", @a.to_s) + a = IPAddr.new("192.168.2.0/24") + assert_equal("192.168.0.0", a.mask(16).to_s) + assert_equal("192.168.0.0", a.mask("255.255.0.0").to_s) + assert_equal("192.168.2.0", a.to_s) + assert_raise(IPAddr::InvalidPrefixError) {a.mask("255.255.0.255")} + assert_raise(IPAddr::InvalidPrefixError) {@a.mask("ffff:1::")} + end + + def test_include? + assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::"))) + assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1"))) + assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::"))) + net1 = IPAddr.new("192.168.2.0/24") + assert_equal(true, net1.include?(IPAddr.new("192.168.2.0"))) + assert_equal(true, net1.include?(IPAddr.new("192.168.2.255"))) + assert_equal(false, net1.include?(IPAddr.new("192.168.3.0"))) + assert_equal(true, net1.include?(IPAddr.new("192.168.2.0/28"))) + assert_equal(false, net1.include?(IPAddr.new("192.168.2.0/16"))) + # test with integer parameter + int = (192 << 24) + (168 << 16) + (2 << 8) + 13 + + assert_equal(true, net1.include?(int)) + assert_equal(false, net1.include?(int+255)) + + end + + def test_native_coerce_mask_addr + assert_equal(IPAddr.new("0.0.0.2/255.255.255.255"), IPAddr.new("::2").native) + assert_equal(IPAddr.new("0.0.0.2/255.255.255.255").to_range, IPAddr.new("::2").native.to_range) + end + + def test_loopback? + assert_equal(true, IPAddr.new('127.0.0.1').loopback?) + assert_equal(true, IPAddr.new('127.127.1.1').loopback?) + assert_equal(false, IPAddr.new('0.0.0.0').loopback?) + assert_equal(false, IPAddr.new('192.168.2.0').loopback?) + assert_equal(false, IPAddr.new('255.0.0.0').loopback?) + assert_equal(true, IPAddr.new('::1').loopback?) + assert_equal(false, IPAddr.new('::').loopback?) + assert_equal(false, IPAddr.new('3ffe:505:2::1').loopback?) + + assert_equal(true, IPAddr.new('::ffff:127.0.0.1').loopback?) + assert_equal(true, IPAddr.new('::ffff:127.127.1.1').loopback?) + assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?) + assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?) + assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:127.x.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:7f00:1').loopback?) + end + + def test_private? + assert_equal(false, IPAddr.new('0.0.0.0').private?) + assert_equal(false, IPAddr.new('127.0.0.1').private?) + + assert_equal(false, IPAddr.new('8.8.8.8').private?) + assert_equal(true, IPAddr.new('10.0.0.0').private?) + assert_equal(true, IPAddr.new('10.255.255.255').private?) + assert_equal(false, IPAddr.new('11.255.1.1').private?) + + assert_equal(false, IPAddr.new('172.15.255.255').private?) + assert_equal(true, IPAddr.new('172.16.0.0').private?) + assert_equal(true, IPAddr.new('172.31.255.255').private?) + assert_equal(false, IPAddr.new('172.32.0.0').private?) + + assert_equal(false, IPAddr.new('190.168.0.0').private?) + assert_equal(true, IPAddr.new('192.168.0.0').private?) + assert_equal(true, IPAddr.new('192.168.255.255').private?) + assert_equal(false, IPAddr.new('192.169.0.0').private?) + + assert_equal(false, IPAddr.new('169.254.0.1').private?) + + assert_equal(false, IPAddr.new('::1').private?) + assert_equal(false, IPAddr.new('::').private?) + + assert_equal(false, IPAddr.new('fb84:8bf7:e905::1').private?) + assert_equal(true, IPAddr.new('fc84:8bf7:e905::1').private?) + assert_equal(true, IPAddr.new('fd84:8bf7:e905::1').private?) + assert_equal(false, IPAddr.new('fe84:8bf7:e905::1').private?) + + assert_equal(false, IPAddr.new('::ffff:0.0.0.0').private?) + assert_equal(false, IPAddr.new('::ffff:127.0.0.1').private?) + + assert_equal(false, IPAddr.new('::ffff:8.8.8.8').private?) + assert_equal(true, IPAddr.new('::ffff:10.0.0.0').private?) + assert_equal(true, IPAddr.new('::ffff:10.255.255.255').private?) + assert_equal(false, IPAddr.new('::ffff:11.255.1.1').private?) + + assert_equal(false, IPAddr.new('::ffff:172.15.255.255').private?) + assert_equal(true, IPAddr.new('::ffff:172.16.0.0').private?) + assert_equal(true, IPAddr.new('::ffff:172.31.255.255').private?) + assert_equal(false, IPAddr.new('::ffff:172.32.0.0').private?) + + assert_equal(false, IPAddr.new('::ffff:190.168.0.0').private?) + assert_equal(true, IPAddr.new('::ffff:192.168.0.0').private?) + assert_equal(true, IPAddr.new('::ffff:192.168.255.255').private?) + assert_equal(false, IPAddr.new('::ffff:192.169.0.0').private?) + + assert_equal(false, IPAddr.new('::ffff:169.254.0.1').private?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:10/172.16/192.168.x + assert_equal(false, IPAddr.new('2001:718:1404:c8:0:ffff:ac19:c80e').private?) + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:c0a8:1').private?) + end + + def test_link_local? + assert_equal(false, IPAddr.new('0.0.0.0').link_local?) + assert_equal(false, IPAddr.new('127.0.0.1').link_local?) + assert_equal(false, IPAddr.new('10.0.0.0').link_local?) + assert_equal(false, IPAddr.new('172.16.0.0').link_local?) + assert_equal(false, IPAddr.new('192.168.0.0').link_local?) + + assert_equal(true, IPAddr.new('169.254.1.1').link_local?) + assert_equal(true, IPAddr.new('169.254.254.255').link_local?) + + assert_equal(false, IPAddr.new('::1').link_local?) + assert_equal(false, IPAddr.new('::').link_local?) + assert_equal(false, IPAddr.new('fb84:8bf7:e905::1').link_local?) + + assert_equal(true, IPAddr.new('fe80::dead:beef:cafe:1234').link_local?) + + assert_equal(false, IPAddr.new('::ffff:0.0.0.0').link_local?) + assert_equal(false, IPAddr.new('::ffff:127.0.0.1').link_local?) + assert_equal(false, IPAddr.new('::ffff:10.0.0.0').link_local?) + assert_equal(false, IPAddr.new('::ffff:172.16.0.0').link_local?) + assert_equal(false, IPAddr.new('::ffff:192.168.0.0').link_local?) + + assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?) + assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:169.254.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:a9fe:101').link_local?) + end + + def test_hash + a1 = IPAddr.new('192.168.2.0') + a2 = IPAddr.new('192.168.2.0') + a3 = IPAddr.new('3ffe:505:2::1') + a4 = IPAddr.new('3ffe:505:2::1') + a5 = IPAddr.new('127.0.0.1') + a6 = IPAddr.new('::1') + a7 = IPAddr.new('192.168.2.0/25') + a8 = IPAddr.new('192.168.2.0/25') + + h = { a1 => 'ipv4', a2 => 'ipv4', a3 => 'ipv6', a4 => 'ipv6', a5 => 'ipv4', a6 => 'ipv6', a7 => 'ipv4', a8 => 'ipv4'} + assert_equal(5, h.size) + assert_equal('ipv4', h[a1]) + assert_equal('ipv4', h[a2]) + assert_equal('ipv6', h[a3]) + assert_equal('ipv6', h[a4]) + + require 'set' + s = Set[a1, a2, a3, a4, a5, a6, a7, a8] + assert_equal(5, s.size) + assert_equal(true, s.include?(a1)) + assert_equal(true, s.include?(a2)) + assert_equal(true, s.include?(a3)) + assert_equal(true, s.include?(a4)) + assert_equal(true, s.include?(a5)) + assert_equal(true, s.include?(a6)) + end + + def test_raises_invalid_address_error_with_error_message + e = assert_raise(IPAddr::InvalidAddressError) do + IPAddr.new('192.168.0.1000') + end + assert_equal('invalid address: 192.168.0.1000', e.message) + + e = assert_raise(IPAddr::InvalidAddressError) do + IPAddr.new('192.168.01.100') + end + assert_equal('zero-filled number in IPv4 address is ambiguous: 192.168.01.100', e.message) + + e = assert_raise(IPAddr::InvalidAddressError) do + IPAddr.new('INVALID') + end + assert_equal('invalid address: INVALID', e.message) + end +end |
