summaryrefslogtreecommitdiff
diff options
-rw-r--r--.document4
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--.github/dependabot.yml6
-rw-r--r--.github/release.yml4
-rw-r--r--.github/workflows/push_gem.yml46
-rw-r--r--.github/workflows/sync-ruby.yml33
-rw-r--r--.github/workflows/test.yml34
-rw-r--r--.gitignore9
-rw-r--r--CHANGELOG.md85
-rw-r--r--Gemfile8
-rw-r--r--Rakefile10
-rw-r--r--debian/changelog12
-rw-r--r--debian/control11
-rw-r--r--debian/copyright2
-rw-r--r--debian/upstream/metadata4
-rw-r--r--debian/watch11
-rw-r--r--ipaddr.gemspec53
-rw-r--r--lib/ipaddr.rb30
-rw-r--r--test/lib/helper.rb4
-rw-r--r--test/test_ipaddr.rb670
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.
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..a91f335
--- /dev/null
+++ b/Gemfile
@@ -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