Browse Source

Testing and serialization.

Beoran 8 years ago
parent
commit
ed53cdd14b
4 changed files with 284 additions and 0 deletions
  1. 177 0
      lib/serdes.rb
  2. 0 0
      test/test_serdes.rb
  3. 60 0
      test/test_sitef.rb
  4. 47 0
      test/woe/test_server.rb

+ 177 - 0
lib/serdes.rb

@@ -0,0 +1,177 @@
+
+class Dir
+  def self.mkdir_p(name)
+    sub   = ""
+    parts = name.split('/').reject { |e| e.empty? }
+    parts.each do | part |
+      sub <<  "/#{part}"
+      mkdir sub
+    end
+  end
+end
+
+
+
+# Module to help with serialization and deserialization of any type of data
+module Serdes
+  
+  module ClassMethods
+    def serdes_add_to_fields(name, type = nil)
+      @serdes_fields ||= []
+      info = { :name => name, :type => type }
+      @serdes_fields << info
+    end
+    
+    def serdes_reader(name, type = nil)
+      serdes_add_to_fields(name, type)
+      attr_reader(name)
+    end
+    
+    def serdes_writer(name)
+      serdes_add_to_fields(name, type = nil)
+      attr_writer(name)
+    end
+    
+    def serdes_accessor(name)
+      serdes_add_to_fields(name, type)
+      attr_accessor(name)
+    end
+    
+    def serdes_fields()
+      @serdes_fields ||= []
+      return @serdes_fields
+    end
+    
+    
+    def serdes_register(obj)
+      @serdes_loaded ||= {}
+      @serdes_loaded[obj.id] = obj
+    end
+    
+    def serdes_forget(id)
+      @serdes_loaded ||= {}
+      @serdes_loaded.delete(id)
+    end
+    
+    def serdes_loaded()
+      @serdes_loaded ||= {}
+      return @serdes_loaded
+    end
+    
+    def serdes_get(id)
+      @serdes_loaded ||= {}
+      return @serdes_loaded[id.to_sym]
+    end
+
+    def serdes_load(id)
+      return nil unless id && !id.empty?
+      
+      full_name = Serdes.serdes_dir_name(self, id) + '/' + Serdes.serdes_file_name(self, id)
+      data, errors  = Sitef.load_filename(full_name)
+      unless data
+        log errors.join(", ")
+        return nil
+      end
+      
+      eldat = data.select do |el|
+        el['id'].to_s == id.to_s
+      end
+      return nil unless eldat
+
+      eldat = eldat.first
+      return nil unless eldat
+      
+      typedat = {}
+      self.serdes_fields.each do |info|
+        name  = info[:name]
+        type  = info[:type]
+        value = eldat[name.to_s]
+        
+        typevalue = nil
+        
+        if type.respond_to?(:serdes_load)
+          typevalue = type.serdes_load(value)
+        elsif type && Kernel.respond_to?(type.to_sym)
+          typevalue = Kernel.send(type.to_sym, value) rescue nil 
+        else
+          typevalue = value
+        end
+      
+        typedat[name] = typevalue
+      end
+      
+      obj = self.new(typedat)
+      return obj
+    end
+    
+    def serdes_fetch(id)
+      res = serdes_get(id)
+      return res if res
+      return serdes_load(id)
+    end
+    
+    alias :fetch :serdes_fetch
+    alias :load  :serdes_load
+    alias :get   :serdes_get
+    
+    def from_serdes(id)
+      return serdes_fetch(id)
+    end
+    
+    def to_serdes(value)
+      return value.id.to_s
+    end  
+  end
+
+  # include callback, be sure to extend the class with the ClassMethods
+  def self.included(klass)
+    klass.extend(ClassMethods)
+  end
+  
+  def self.serdes_dir_name(klass)
+    top = klass.to_s.gsub('::', '/').downcase
+    return top
+  end
+  
+  def self.serdes_file_name(id)
+    top = id.to_s.dup    
+    top << '.sitef'
+    return top 
+  end
+
+  def serdes_data
+    data = {}
+    self.class.serdes_fields.each do |info|
+      name  = info[:name]
+      type  = info[:type]
+      type||= String
+      key   = "#{name}" 
+      value = "#{self.send(name.to_sym)}"
+      if type.respond_to?(:to_serdes)
+         wrapvalue = type.to_serdes(value)
+      else 
+         wrapvalue = value.to_s
+      end
+      data[key]    = wrapvalue
+    end
+    return data
+  end
+  
+  def save
+    Dir.mkdir_p Serdes.serdes_dir_name(self.class, self.id)
+    data = serdes_data
+    full_name = Serdes.serdes_dir_name(self.class, self.id) + 
+               '/' + Serdes.serdes_file_name(self.class, self.id)
+    Sitef.save_filename(full_name, [ data ] )
+  end
+  
+  def initialize(fields = {}) 
+    fields.each  do |key, value|
+      p "Setting #{key} #{value}"
+      instance_variable_set("@#{key}", value)
+    end
+    self.class.serdes_register(self)
+  end
+
+end
+

+ 0 - 0
test/test_serdes.rb


+ 60 - 0
test/test_sitef.rb

@@ -0,0 +1,60 @@
+require 'atto'
+include Atto::Test
+
+require_relative '../lib/sitef' 
+
+SITEF_NAME = '/tmp/sitef_test.sitef'
+SITEF_NAME2 = '/tmp/sitef_test2.sitef'
+TEST_DATA = []
+TEST_DATA <<  { :nid => 10, :text => "I'm a 10 text man\nAnd I go on several\nlines." }
+TEST_DATA <<  { :nid => 27, :text => "--\nA tricky text. 3 newlines:\n\n\nSlashes: \n\\\n:nid:27\n\n.text\n.." }
+
+module Foo
+class Try
+  attr_reader :foo  
+  attr_reader :bar
+  
+  def initialize (h = {})
+    @foo = h['foo']
+    @bar = h['bar']
+  end
+  
+  def self.from_sitef(h)
+    self.new(h)
+  end
+  
+end
+end
+
+TEST_DATA2 = [ Foo::Try.new('foo' => 1, 'bar' => "Yeah"),  
+Foo::Try.new('foo' => 1, 'bar' => "Oh")]
+  
+
+assert { Sitef } 
+assert { Sitef.save_filename(SITEF_NAME, TEST_DATA) }
+
+assert "Loading" do
+  res, err = Sitef.load_filename(SITEF_NAME)
+  p res
+  res && err.empty? && res[0]["nid"] == "10" && res[1]["nid"] == "27"
+end
+
+
+assert "Text round trip" do
+  res, err = Sitef.load_filename(SITEF_NAME)
+  to = TEST_DATA[1][:text]
+  tl = res[1]["text"]
+  p to, tl
+  to == tl
+end
+
+assert do
+  Sitef.save_filename(SITEF_NAME2, TEST_DATA2, :foo, :bar) 
+end
+
+
+assert do
+  res, err = Sitef.load_objects(SITEF_NAME2)
+  p res
+  res
+end

+ 47 - 0
test/woe/test_server.rb

@@ -0,0 +1,47 @@
+require 'atto'
+include Atto::Test
+
+require_relative '../../lib/woe/client' 
+require_relative '../../lib/woe/server' 
+
+assert { Woe::Server }
+
+# Fork off the server so the Net::Telnet tests can procede
+pid = Process.fork do 
+  Woe::Server.run
+  # exit here to ge
+  puts __FILE__ + ' Server Done'
+  exit 0
+end
+
+p pid
+
+assert { pid }
+
+require 'net/telnet'
+
+
+assert do
+  sleep 1
+  client = Net::Telnet.new('Host' => 'localhost', 'Port' => 7000, 
+                            'Timeout' => 3)
+  res    = client.waitfor(/Login:/)
+  client.write("Axl\n")
+  client.waitfor(/.*/)
+  client.write("pass\n")
+  client.waitfor(/.*/)
+  client.write("hello\n")
+  client.waitfor(/.*/)
+  client.write("/quit\n")
+  client.waitfor(/.*/)
+  client.close
+  ok = !!client
+  ok  
+end
+
+
+# Finally stop the server and wait for it to finish
+Process.kill(:TERM, pid)
+Process.wait(pid)
+ puts __FILE__ + ' Tests Done'
+