From cf49ea94c9e580780508f07c1352ef1252018d0f Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman <the@jeffreyfreeman.me> Date: Fri, 4 Aug 2023 23:23:06 -0400 Subject: [PATCH] Updated frame to be a class rather than a map --- CHANGELOG.md | 5 +- lib/apex/aprs_kiss.rb | 18 +++--- lib/apex/frame.rb | 124 ++++++++++++++++++++++++++++++++++++++++++ lib/apex/igate_tcp.rb | 22 ++++---- test/tc_aprs_kiss.rb | 27 ++++----- test/tc_frame.rb | 122 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 284 insertions(+), 34 deletions(-) create mode 100644 lib/apex/frame.rb create mode 100644 test/tc_frame.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 721ec45..f1087bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,12 @@ ## 1.0.4 +* Frames are now classes rather than a map +* Added mechanism for comparing frames for equivalence. + ## 1.0.3 -* Implemented the IGateTcp class for handking internet gateways. +* Implemented the IGateTcp class for handling internet gateways. ## 1.0.2 diff --git a/lib/apex/aprs_kiss.rb b/lib/apex/aprs_kiss.rb index 572126d..b0c450e 100644 --- a/lib/apex/aprs_kiss.rb +++ b/lib/apex/aprs_kiss.rb @@ -1,4 +1,5 @@ require 'kiss/constants' +require 'apex/frame' module Apex class AprsKiss @@ -11,7 +12,6 @@ module Apex private def self.decode_frame(raw_frame) - frame = {} frame_len = raw_frame.length if frame_len > 16 @@ -23,11 +23,11 @@ module Apex if 1.0 < i and i < 11.0 if raw_frame[raw_slice + 1] & 0x03 == 0x03 and [0xf0, 0xcf].include? raw_frame[raw_slice + 2] payload_as_array = raw_frame[raw_slice + 3..-1].map { |b| b.chr } - frame[:payload] = payload_as_array.join - frame[:destination] = identity_as_string(extract_callsign(raw_frame)) - frame[:source] = identity_as_string(extract_callsign(raw_frame[7..-1])) - frame[:path] = extract_path(i.to_i, raw_frame) - return frame + payload = payload_as_array.join + destination = identity_as_string(extract_callsign(raw_frame)) + source = identity_as_string(extract_callsign(raw_frame[7..-1])) + path = extract_path(i.to_i, raw_frame) + return Frame.new(source, destination, path, payload) end end end @@ -94,13 +94,13 @@ module Apex private def self.encode_frame(frame) - enc_frame = encode_callsign(parse_identity_string(frame[:destination])) + encode_callsign(parse_identity_string(frame[:source])) + enc_frame = encode_callsign(parse_identity_string(frame.destination)) + encode_callsign(parse_identity_string(frame.source)) - frame[:path].each do |path| + frame.path.each do |path| enc_frame += encode_callsign(parse_identity_string(path)) end - return enc_frame[0...-1] + [enc_frame[-1] | 0x01] + [Kiss::SLOT_TIME] + [0xf0] + frame[:payload].chars.map { |c| c.ord } + return enc_frame[0...-1] + [enc_frame[-1] | 0x01] + [Kiss::SLOT_TIME] + [0xf0] + frame.payload.chars.map { |c| c.ord } end private diff --git a/lib/apex/frame.rb b/lib/apex/frame.rb new file mode 100644 index 0000000..e1a6093 --- /dev/null +++ b/lib/apex/frame.rb @@ -0,0 +1,124 @@ +module Apex + public + class UnpathedFrame + attr_accessor :source, :destination, :payload + + protected + def initialize(source, destination, payload) + @source = source + @destination = destination + @payload = payload + end + + public + def path_agnostic_eql?(other) + raise ArgumentError.new("The argument must be either an UnpathedFrame or a PathAgnosticFrame") if not ((other.instance_of? UnpathedFrame) || (other.instance_of? PathAgnosticFrame)) + + return self == other + end + + public + def path_agnostic_equality?(other) + return false if (not other.respond_to? :source) || + (not other.respond_to? :destination) || + (not other.respond_to? :payload) + + if (self.source.eql? other.source) && (self.destination.eql? other.destination) && (self.payload.eql? other.payload) + return true + else + return false + end + end + + public + def path_agnostic_hash + return [self.source, self.destination, self.payload].hash + end + + public + def ==(other) + return self.path_agnostic_equality? other + end + + public + def eql?(other) + self.path_agnostic_eql? other + end + + public + def hash + return self.path_agnostic_hash + end + end + + public + class Frame < UnpathedFrame + attr_accessor :path + + protected + def initialize(source, destination, path, payload) + super(source, destination, payload) + + @path = path + end + + public + def eql?(other) + raise ArgumentError.new("The argument can not be a UnpathedFrame or a PathAgnosticFrame") if ((other.instance_of? UnpathedFrame) || (other.instance_of? PathAgnosticFrame)) + raise ArgumentError.new("The argument must be of type Frame (or a child class).") if not other.kind_of? Frame + + return self == other + end + + public + def ==(other) + return false if not super(other) + + return false if not other.respond_to? :path + + if self.path.eql? other.path + return true + else + return false + end + end + + public + def hash + return [super, self.path].hash + end + + public + def path_agnostic_identity + return PathAgnosticFrame.new(self) + end + end + + private + class PathAgnosticFrame < Frame + protected + def initialize(frame) + super(frame.source, frame.destination, frame.path, frame.payload) + end + + public + def eql?(other) + return self.path_agnostic_eql? other + end + + public + def ==(other) + return self.path_agnostic_equality? other + end + + public + def hash + return self.path_agnostic_hash + end + + public + def path_agnostic_identity + return self + end + end +end diff --git a/lib/apex/igate_tcp.rb b/lib/apex/igate_tcp.rb index 6b5aa2a..09aa6cd 100644 --- a/lib/apex/igate_tcp.rb +++ b/lib/apex/igate_tcp.rb @@ -30,23 +30,23 @@ module Apex private def self.encode_frame(frame) - formatted_frame = [frame[:source], frame[:destination]].join('>') - if frame[:path] and frame[:path].length > 0 - formatted_frame = [formatted_frame, IGateTcp::format_path(frame[:path])].join(',') + formatted_frame = [frame.source, frame.destination].join('>') + if frame.path and frame.path.length > 0 + formatted_frame = [formatted_frame, IGateTcp::format_path(frame.path)].join(',') end formatted_frame += ':' - formatted_frame += frame[:payload] + formatted_frame += frame.payload return formatted_frame end private def self.decode_frame(frame) - decoded_frame = {} + decoded_source = nil frame_so_far = '' path = nil frame.chars.each do |char| - if char == '>' and !decoded_frame.include? :source - decoded_frame[:source] = frame_so_far + if char == '>' and decoded_source.nil? + decoded_source = frame_so_far frame_so_far = '' elsif char == ':' and !path path = frame_so_far @@ -57,11 +57,11 @@ module Apex end path = path.split(',') - decoded_frame[:destination] = path.shift - decoded_frame[:path] = path - decoded_frame[:payload] = frame_so_far + decoded_destination = path.shift + decoded_path = path + decoded_payload = frame_so_far - decoded_frame + return Frame.new(decoded_source, decoded_destination, decoded_path, decoded_payload) end private diff --git a/test/tc_aprs_kiss.rb b/test/tc_aprs_kiss.rb index c5058c5..7681c9d 100644 --- a/test/tc_aprs_kiss.rb +++ b/test/tc_aprs_kiss.rb @@ -1,30 +1,31 @@ require 'test/unit' require 'kiss/test/kiss_mock' require_relative '../lib/apex/aprs_kiss' +require_relative '../lib/apex/frame' module Apex - DECODED_FRAME_KISS = { - :source => 'W2GMD-1', - :destination => 'OMG', - :path => ['WIDE1-1', 'WIDE2-2'], - :payload => 'test_encode_frame' - } + DECODED_FRAME_KISS = Apex::Frame.new( + 'W2GMD-1', + 'OMG', + ['WIDE1-1', 'WIDE2-2'], + 'test_encode_frame' + ) ENCODED_FRAME_KISS = [192, 0, 158, 154, 142, 64, 64, 64, 96, 174, 100, 142, 154, 136, 64, 98, 174, 146, 136, 138, 98, 64, 98, 174, 146, 136, 138, 100, 64, 101, 3, 240, 116, 101, 115, 116, 95, 101, 110, 99, 111, 100, 101, 95, 102, 114, 97, 109, 101, 192] - DECODED_FRAME_KISS_INVALID = { - :source => 'KG6WTF', - :destination => 'S7TSUV', - :path => ['MTOSO-2', 'WIDE2*' 'qAR', 'KF6FIR-10'], - :payload => '`17El#X-/kg6wtf@gosselinfamily.com' - } + DECODED_FRAME_KISS_INVALID = Apex::Frame.new( + 'KG6WTF', + 'S7TSUV', + ['MTOSO-2', 'WIDE2*' 'qAR', 'KF6FIR-10'], + '`17El#X-/kg6wtf@gosselinfamily.com' + ) ENCODED_FRAME_KISS_INVALID = [192, 0, 166, 110, 168, 166, 170, 172, 96, 150, 142, 108, 174, 168, 140, 96, 154, 168, 158, 166, 158, 64, 100, 174, 146, 136, 138, 100, 226, 130, 164, 224, 150, 140, 108, 140, 146, 164, 117, 3, 240, 96, 49, 55, 69, 108, 35, 88, 45, 47, 107, 103, 54, 119, 116, 102, 64, 103, 111, 115, 115, 101, 108, 105, 110, 102, 97, 109, 105, 108, 121, 46, 99, 111, 109, 192] - class TestKiss < Test::Unit::TestCase + class TestAprsKiss < Test::Unit::TestCase def test_read kiss_mock = Kiss::KissMock.new aprs_kiss = AprsKiss.new(kiss_mock) diff --git a/test/tc_frame.rb b/test/tc_frame.rb new file mode 100644 index 0000000..5463378 --- /dev/null +++ b/test/tc_frame.rb @@ -0,0 +1,122 @@ +module Apex + BASE_FRAME = Apex::Frame.new( + 'WI2ARD-1', + 'OMG', + ['WIDE2-2' 'WIDE1-1'], + 'payload goes here' + ) + + SAME_BASE_FRAME = Apex::Frame.new( + 'WI2ARD-1', + 'OMG', + ['WIDE2-2' 'WIDE1-1'], + 'payload goes here' + ) + + DIFF_PATH_FRAME = Apex::Frame.new( + 'WI2ARD-1', + 'OMG', + ['WIDE2-1' 'WIDE1-1'], + 'payload goes here' + ) + + DIFF_SOURCE_FRAME = Apex::Frame.new( + 'WI2ARD-2', + 'OMG', + ['WIDE2-2' 'WIDE1-1'], + 'payload goes here' + ) + + DIFF_DEST_FRAME = Apex::Frame.new( + 'WI2ARD-1', + 'LOL', + ['WIDE2-2' 'WIDE1-1'], + 'payload goes here' + ) + + DIFF_PAYLOAD_FRAME = Apex::Frame.new( + 'WI2ARD-1', + 'OMG', + ['WIDE2-2' 'WIDE1-1'], + 'totally different payload here' + ) + + class TestFrame < Test::Unit::TestCase + def test_self_frame + assert BASE_FRAME.eql? BASE_FRAME + assert BASE_FRAME.hash.eql? BASE_FRAME.hash + end + + def test_same_frame + assert BASE_FRAME.eql? SAME_BASE_FRAME + assert BASE_FRAME.hash.eql? SAME_BASE_FRAME.hash + end + + def test_same_frame_path_agnostic + agnostic_frame = BASE_FRAME.path_agnostic_identity + agnostic_other_frame = SAME_BASE_FRAME.path_agnostic_identity + assert agnostic_frame.eql? agnostic_other_frame + assert agnostic_frame.hash.eql? agnostic_other_frame.hash + end + + def test_diff_path_frame + assert (not BASE_FRAME.eql? DIFF_PATH_FRAME) + assert (not BASE_FRAME.hash.eql? DIFF_PATH_FRAME.hash) + end + + def test_diff_path_frame_path_agnostic + agnostic_frame = BASE_FRAME.path_agnostic_identity + agnostic_other_frame = DIFF_PATH_FRAME.path_agnostic_identity + assert agnostic_frame.eql? agnostic_other_frame + assert agnostic_frame.hash.eql? agnostic_other_frame.hash + end + + def test_diff_source_frame + assert (not BASE_FRAME.eql? DIFF_SOURCE_FRAME) + assert (not BASE_FRAME.hash.eql? DIFF_SOURCE_FRAME.hash) + end + + def test_diff_source_frame_path_agnostic + agnostic_frame = BASE_FRAME.path_agnostic_identity + agnostic_other_frame = DIFF_SOURCE_FRAME.path_agnostic_identity + assert (not agnostic_frame.eql? agnostic_other_frame) + assert (not agnostic_frame.hash.eql? agnostic_other_frame.hash) + end + + def test_diff_dest_frame + assert (not BASE_FRAME.eql? DIFF_DEST_FRAME) + assert (not BASE_FRAME.hash.eql? DIFF_DEST_FRAME.hash) + end + + def test_diff_dest_frame_path_agnostic + agnostic_frame = BASE_FRAME.path_agnostic_identity + agnostic_other_frame = DIFF_DEST_FRAME.path_agnostic_identity + assert (not agnostic_frame.eql? agnostic_other_frame) + assert (not agnostic_frame.hash.eql? agnostic_other_frame.hash) + end + + def test_diff_payload_frame + assert (not BASE_FRAME.eql? DIFF_PAYLOAD_FRAME) + assert (not BASE_FRAME.hash.eql? DIFF_PAYLOAD_FRAME.hash) + end + + def test_diff_payload_frame_path_agnostic + agnostic_frame = BASE_FRAME.path_agnostic_identity + agnostic_other_frame = DIFF_PAYLOAD_FRAME.path_agnostic_identity + assert (not agnostic_frame.eql? agnostic_other_frame) + assert (not agnostic_frame.hash.eql? agnostic_other_frame.hash) + end + + def test_bad_type + assert_raise ArgumentError do + BASE_FRAME.eql? BASE_FRAME.path_agnostic_identity + end + end + + def test_bad_type_agnostic + assert_raise ArgumentError do + BASE_FRAME.path_agnostic_identity.eql? BASE_FRAME + end + end + end +end -- GitLab