Commits

Erik Grinaker  committed 8f4600f

rewrote the netrc data handler, and wrote unit tests for it

  • Participants
  • Parent commits 07c1fb2

Comments (0)

Files changed (4)

 
 ---------------[ xxxx-xx-xx : 0.4.0 ]---------------
 
+2005-01-05  Erik Grinaker <erikg@codepoet.no>
+
+	* rewrote the netrc datahandler, and wrote unit tests for it
+
+
 2005-01-04  Erik Grinaker <erikg@codepoet.no>
 
 	* don't subclass gnome.ui.HRef (abstract widget from
   - add remote desktop account type
   - clean up the account types
   - possibility for custom account types
-  - add "note" entry type
+  - add "note" entry type (large field for free-text data)
 - file merging (union - this *really* need unique entry ids)
 - accessibility improvements
 - help / documentation

File src/lib/datahandler/netrc.py

 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #
 
-import revelation, base
-import StringIO, shlex, time, gtk
+import base
+from revelation import data, entry
+
+import shlex, StringIO, time
 
 
 class NetRC(base.DataHandler):
 	"Data handler for .netrc data"
 
-	name		= ".netrc"
-	importer	= gtk.TRUE
-	exporter	= gtk.TRUE
-	encryption	= gtk.FALSE
+	name		= "netrc"
+	importer	= True
+	exporter	= True
+	encryption	= False
 
 
-	def export_data(self, entrystore):
-		"Converts data from an entrystore into a data stream"
+	def export_data(self, entrystore, password = None):
+		"Converts data from an entrystore to netrc data"
 
-		data = ""
+		netrc = ""
 		iter = entrystore.iter_nth_child(None, 0)
 
 		while iter is not None:
+			e = entrystore.get_entry(iter)
 
-			entry = entrystore.get_entry(iter)
+			try:
+				if "" in ( e[entry.HostnameField], e[entry.UsernameField], e[entry.PasswordField] ):
+					raise ValueError
 
-			# only export entries which have a hostname, username and password
-			if not entry.has_field(revelation.entry.HostnameField) or not entry.has_field(revelation.entry.UsernameField) or not entry.has_field(revelation.entry.PasswordField):
-				iter = entrystore.iter_traverse_next(iter)
-				continue
+				if e.name != "":
+					netrc += "# %s\n" % e.name
 
-			hostname = entry.get_field(revelation.entry.HostnameField).value
-			username = entry.get_field(revelation.entry.UsernameField).value
-			password = entry.get_field(revelation.entry.PasswordField).value
+				if e.description != "":
+					netrc += "# %s\n" % e.description
 
-			if hostname == "" or username == "" or password == "":
-				iter = entrystore.iter_traverse_next(iter)
-				continue
+				netrc += "machine %s\n" % e[entry.HostnameField]
+				netrc += "	login %s\n" % e[entry.UsernameField]
+				netrc += "	password %s\n" % e[entry.PasswordField]
+				netrc += "\n"
 
-
-			# add name and description as comments, if any
-			if entry.name != "":
-				data += "# " + entry.name + "\n"
-
-			if entry.description != "":
-				data += "# " + entry.description + "\n"
-
-
-			# export the entry itself
-			data += "machine " + hostname + "\n"
-			data += "	login " + username + "\n"
-			data += "	password " + password + "\n"
-			data += "\n"
+			except ( entry.EntryFieldError, ValueError ):
+				pass
 
 			iter = entrystore.iter_traverse_next(iter)
 
-		return data
+		return netrc
 
 
-	def import_data(self, data):
-		"Imports data from a data stream into an entrystore"
+	def import_data(self, netrc, password = None):
+		"Imports data from a netrc stream to an entrystore"
 
-		entrystore = revelation.data.EntryStore()
+		entrystore = data.EntryStore()
 
 		# set up a lexical parser
-		datafp = StringIO.StringIO(data)
+		datafp = StringIO.StringIO(netrc)
 		lexer = shlex.shlex(datafp)
 		lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
 
 
 
 			# we're looking at an entry, so fetch data
-			entry = revelation.entry.GenericEntry()
-			entry.name = name
-			entry.updated = time.time()
+			e = entry.GenericEntry()
+			e.name = name
+			e.updated = time.time()
 
 			if name != "default":
-				entry.get_field(revelation.entry.HostnameField).value = name
+				e[entry.HostnameField] = name
 
 			while 1:
 				tt = lexer.get_token()
 
 				# if we find a new entry, break out of current field-collecting loop
 				if tt == "" or tt == "machine" or tt == "default" or tt == "macdef":
-					entrystore.add_entry(None, entry)
+					entrystore.add_entry(e)
 					lexer.push_token(tt)
 					break
 
 				elif tt == "login" or tt == "user":
-					entry.get_field(revelation.entry.UsernameField).value = lexer.get_token()
+					e[entry.UsernameField] = lexer.get_token()
 
 				elif tt == "account":
 					lexer.get_token()
 
 				elif tt == "password":
-					entry.get_field(revelation.entry.PasswordField).value = lexer.get_token()
+					e[entry.PasswordField] = lexer.get_token()
 
 				else:
 					raise base.FormatError

File test/datahandler_netrc.py

+#!/usr/bin/env python
+
+#
+# Revelation 0.4.0 - a password manager for GNOME 2
+# http://oss.codepoet.no/revelation/
+# $Id$
+#
+# Unit tests for NetRC datahandler module
+#
+#
+# Copyright (c) 2003-2005 Erik Grinaker
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+
+import unittest
+
+from revelation import data, datahandler, entry
+
+
+class NetRC(unittest.TestCase):
+	"NetRC"
+
+	def test_attrs(self):
+		"NetRC has sane attrs"
+
+		self.assertEquals(datahandler.NetRC.name, "netrc")
+		self.assertEquals(datahandler.NetRC.importer, True)
+		self.assertEquals(datahandler.NetRC.exporter, True)
+		self.assertEquals(datahandler.NetRC.encryption, False)
+
+
+
+class NetRC_export_data(unittest.TestCase):
+	"NetRC.export_data()"
+
+	def setUp(self):
+		"Sets up common facilities for testing"
+
+		self.entrystore = data.EntryStore()
+
+		e = entry.GenericEntry()
+		e.name = "name"
+		e.description = "description"
+		e.updated = 12345678
+		e[entry.HostnameField] = "hostname"
+		e[entry.UsernameField] = "username"
+		e[entry.PasswordField] = "password"
+		self.entrystore.add_entry(e)
+
+		e = entry.WebEntry()
+		e.name = "website"
+		e[entry.URLField] = "url"
+		e[entry.UsernameField] = "username"
+		e[entry.PasswordField] = "password"
+		self.entrystore.add_entry(e)
+
+		fiter = self.entrystore.add_entry(entry.FolderEntry())
+
+		e = entry.GenericEntry()
+		e.name = "name2"
+		e.description = "description2"
+		e.updated = 87654321
+		e[entry.HostnameField] = "hostname2"
+		e[entry.UsernameField] = "username2"
+		e[entry.PasswordField] = "password2"
+		self.entrystore.add_entry(e, fiter)
+
+		e = entry.GenericEntry()
+		e.name = "test"
+		e[entry.UsernameField] = "username"
+		e[entry.PasswordField] = "password"
+		self.entrystore.add_entry(e)
+
+
+		self.testdata = """\
+# name
+# description
+machine hostname
+	login username
+	password password
+
+# name2
+# description2
+machine hostname2
+	login username2
+	password password2
+
+"""
+
+
+	def test_data(self):
+		"NetRC.export_data() generates correct data"
+
+		self.assertEquals(datahandler.NetRC().export_data(self.entrystore), self.testdata)
+
+
+
+class NetRC_import_data(unittest.TestCase):
+	"NetRC.import_data()"
+
+	def test_data(self):
+		"Checks if NetRC imports data correctly"
+
+		netrc = """
+# name
+# description
+machine hostname
+	login username
+	password password
+
+# name2
+# description2
+machine hostname2
+	login username2
+	password password2
+"""
+
+		entrystore = datahandler.NetRC().import_data(netrc)
+
+		self.assertEquals(entrystore.iter_n_children(None), 2)
+
+		e = entrystore.get_entry(entrystore.iter_nth_child(None, 0))
+		self.assertEquals(type(e), entry.GenericEntry)
+		self.assertEquals(e.name, "hostname")
+		self.assertNotEqual(e.updated, 0)
+		self.assertEquals(e[entry.HostnameField], "hostname")
+		self.assertEquals(e[entry.UsernameField], "username")
+		self.assertEquals(e[entry.PasswordField], "password")
+
+		e = entrystore.get_entry(entrystore.iter_nth_child(None, 1))
+		self.assertEquals(type(e), entry.GenericEntry)
+		self.assertEquals(e.name, "hostname2")
+		self.assertNotEqual(e.updated, 0)
+		self.assertEquals(e[entry.HostnameField], "hostname2")
+		self.assertEquals(e[entry.UsernameField], "username2")
+		self.assertEquals(e[entry.PasswordField], "password2")
+
+
+	def test_format(self):
+		"NetRC.import_data() raises FormatError on invalid format"
+
+		netrc = """
+# name
+# description
+machine hostname
+	login username
+	password password
+
+oops
+"""
+
+		self.assertRaises(datahandler.FormatError, datahandler.NetRC().import_data, netrc)
+
+
+
+if __name__ == "__main__":
+	unittest.main()
+