weft-qda 0.9.6 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/lib/weft.rb +16 -1
  2. data/lib/weft/WEFT-VERSION-STRING.rb +1 -1
  3. data/lib/weft/application.rb +17 -74
  4. data/lib/weft/backend.rb +6 -32
  5. data/lib/weft/backend/sqlite.rb +222 -164
  6. data/lib/weft/backend/sqlite/category_tree.rb +52 -48
  7. data/lib/weft/backend/sqlite/database.rb +57 -0
  8. data/lib/weft/backend/sqlite/upgradeable.rb +7 -0
  9. data/lib/weft/broadcaster.rb +90 -0
  10. data/lib/weft/category.rb +139 -47
  11. data/lib/weft/codereview.rb +160 -0
  12. data/lib/weft/coding.rb +74 -23
  13. data/lib/weft/document.rb +23 -10
  14. data/lib/weft/exceptions.rb +10 -0
  15. data/lib/weft/filters.rb +47 -224
  16. data/lib/weft/filters/indexers.rb +137 -0
  17. data/lib/weft/filters/input.rb +118 -0
  18. data/lib/weft/filters/output.rb +101 -0
  19. data/lib/weft/filters/templates.rb +80 -0
  20. data/lib/weft/filters/win32backtick.rb +246 -0
  21. data/lib/weft/query.rb +169 -0
  22. data/lib/weft/wxgui.rb +349 -294
  23. data/lib/weft/wxgui/constants.rb +43 -0
  24. data/lib/weft/wxgui/controls.rb +6 -0
  25. data/lib/weft/wxgui/controls/category_dropdown.rb +192 -0
  26. data/lib/weft/wxgui/controls/category_tree.rb +314 -0
  27. data/lib/weft/wxgui/controls/document_list.rb +97 -0
  28. data/lib/weft/wxgui/controls/multitype_control.rb +37 -0
  29. data/lib/weft/wxgui/{inspectors → controls}/textcontrols.rb +235 -64
  30. data/lib/weft/wxgui/dialogs.rb +144 -41
  31. data/lib/weft/wxgui/error_handler.rb +116 -36
  32. data/lib/weft/wxgui/exceptions.rb +7 -0
  33. data/lib/weft/wxgui/inspectors.rb +61 -208
  34. data/lib/weft/wxgui/inspectors/category.rb +19 -16
  35. data/lib/weft/wxgui/inspectors/codereview.rb +90 -132
  36. data/lib/weft/wxgui/inspectors/document.rb +12 -8
  37. data/lib/weft/wxgui/inspectors/imagedocument.rb +56 -56
  38. data/lib/weft/wxgui/inspectors/query.rb +284 -0
  39. data/lib/weft/wxgui/inspectors/script.rb +147 -23
  40. data/lib/weft/wxgui/lang/en.rb +69 -0
  41. data/lib/weft/wxgui/sidebar.rb +90 -432
  42. data/lib/weft/wxgui/utilities.rb +70 -91
  43. data/lib/weft/wxgui/workarea.rb +150 -43
  44. data/share/icons/category.ico +0 -0
  45. data/share/icons/category.xpm +109 -0
  46. data/share/icons/codereview.ico +0 -0
  47. data/share/icons/codereview.xpm +54 -0
  48. data/share/icons/d_and_c.xpm +126 -0
  49. data/share/icons/document.ico +0 -0
  50. data/share/icons/document.xpm +70 -0
  51. data/share/icons/project.ico +0 -0
  52. data/share/icons/query.ico +0 -0
  53. data/share/icons/query.xpm +56 -0
  54. data/{lib/weft/wxgui → share/icons}/search.xpm +0 -0
  55. data/share/icons/weft.ico +0 -0
  56. data/share/icons/weft.xpm +62 -0
  57. data/share/icons/weft16.ico +0 -0
  58. data/share/icons/weft32.ico +0 -0
  59. data/share/templates/category_plain.html +18 -0
  60. data/share/templates/codereview_plain.html +18 -0
  61. data/share/templates/document_plain.html +13 -0
  62. data/share/templates/document_plain.txt +7 -0
  63. data/test/001-document.rb +55 -36
  64. data/test/002-category.rb +81 -6
  65. data/test/003-code.rb +8 -4
  66. data/test/004-application.rb +13 -34
  67. data/test/005-query_review.rb +139 -0
  68. data/test/006-filters.rb +54 -42
  69. data/test/007-output_filters.rb +113 -0
  70. data/test/009a-backend_sqlite_basic.rb +95 -24
  71. data/test/009b-backend_sqlite_complex.rb +43 -62
  72. data/test/009c_backend_sqlite_bench.rb +5 -10
  73. data/test/053-doc_inspector.rb +46 -0
  74. data/test/055-query_window.rb +50 -0
  75. data/test/all-tests.rb +1 -0
  76. data/test/test-common.rb +19 -0
  77. data/test/testdata/empty.qdp +0 -0
  78. data/test/testdata/simple with space.pdf +0 -0
  79. data/test/testdata/simple.pdf +0 -0
  80. data/weft-qda.rb +40 -7
  81. metadata +74 -14
  82. data/lib/weft/wxgui/category.xpm +0 -26
  83. data/lib/weft/wxgui/document.xpm +0 -25
  84. data/lib/weft/wxgui/inspectors/search.rb +0 -265
  85. data/lib/weft/wxgui/mondrian.xpm +0 -44
  86. data/lib/weft/wxgui/weft16.xpm +0 -31
@@ -0,0 +1,139 @@
1
+ require 'test-common'
2
+
3
+ require 'weft'
4
+ require 'test/unit'
5
+
6
+ class TestCodeReview < Test::Unit::TestCase
7
+ include QDA
8
+ def test_to_query()
9
+ cr = CodeReview.new()
10
+ assert_equal(0, cr.number_rows)
11
+ assert_equal(0, cr.number_cols)
12
+
13
+ cat1 = Category.new('foo')
14
+ cat1.code(1, 10, 40)
15
+ cat2 = Category.new('bar')
16
+ cat2.code(1, 70, 20)
17
+ cat3 = Category.new('baz')
18
+ cat3.code(1, 40, 40)
19
+ cat4 = Category.new('qux')
20
+ cat4.code(1, 100, 15)
21
+
22
+ cr.add_col( cat1 )
23
+ cr.add_col( cat2 )
24
+ cr.add_row( cat3 )
25
+ cr.add_row( cat4 )
26
+ # invalid
27
+ assert_nil( cr.to_query(nil, 2,2) )
28
+ # valid
29
+ assert_kind_of( Query, cr.to_query(nil, 0, 1) )
30
+ end
31
+
32
+ def test_basic
33
+ cr = CodeReview.new()
34
+ assert_equal(0, cr.number_rows)
35
+ assert_equal(0, cr.number_cols)
36
+
37
+ cat1 = Category.new('foo')
38
+ cat1.code(1, 10, 40)
39
+ cat2 = Category.new('bar')
40
+ cat2.code(1, 70, 20)
41
+ cat3 = Category.new('baz')
42
+ cat3.code(1, 40, 40)
43
+ cat4 = Category.new('qux')
44
+ cat4.code(1, 100, 15)
45
+
46
+ cr.add_col( cat1 )
47
+ cr.add_col( cat2 )
48
+ assert_equal(0, cr.number_rows)
49
+ assert_equal(2, cr.number_cols)
50
+
51
+ cr.add_row( cat3 )
52
+ cr.add_row( cat4 )
53
+ assert_equal(2, cr.number_rows)
54
+ assert_equal(2, cr.number_cols)
55
+
56
+
57
+ end
58
+ end
59
+
60
+
61
+ # for testing
62
+ class NullFunction < QDA::Query::Function
63
+ def initialize(token)
64
+ @token = token
65
+ end
66
+ def calculate()
67
+ QDA::CodingTable.new()
68
+ end
69
+ def to_s()
70
+ "(NULL-#{@token})"
71
+ end
72
+ end
73
+
74
+ class TestQuery < Test::Unit::TestCase
75
+ include QDA
76
+
77
+ def test_query
78
+ q = Query.new( NullFunction.new('FOO') )
79
+ assert_equal(1, q.num_functions)
80
+ assert_equal(0, q.num_expressions)
81
+ assert_equal(QDA::CodingTable.new(), q.calculate)
82
+ assert_kind_of(NullFunction, q.root)
83
+
84
+ q.add_expression( 'AND', NullFunction.new('BAR') )
85
+ assert_equal(2, q.num_functions)
86
+ assert_equal(1, q.num_expressions)
87
+ assert_equal(QDA::CodingTable.new(), q.calculate)
88
+ assert_kind_of(Query::AND, q.root)
89
+
90
+ q.add_expression( 'OR', NullFunction.new('BAZ') )
91
+ assert_equal(3, q.num_functions)
92
+ assert_equal(2, q.num_expressions)
93
+ assert_equal(QDA::CodingTable.new(), q.calculate)
94
+ assert_kind_of(Query::OR, q.root)
95
+ # a bad logical operator
96
+ assert_raises(ArgumentError) do
97
+ q.add_expression('UG', NullFunction.new('QUX'))
98
+ end
99
+
100
+ end
101
+
102
+
103
+
104
+ def test_or
105
+ cs_1 = CodingTable.new()
106
+ cs_2 = CodingTable.new()
107
+ cs_1.add( Code.new(3, 0, 4) )
108
+ cs_2.add( Code.new(3, 3, 5) )
109
+ expr = Query::AND.new(cs_1, cs_2)
110
+ result = expr.calculate()
111
+ assert_equal(1, result.num_of_docs)
112
+ assert_equal(1, result.num_of_chars)
113
+ assert_equal(1, result.num_of_passages)
114
+ end
115
+
116
+ def test_and_not
117
+ cs_1 = CodingTable.new()
118
+ cs_2 = CodingTable.new()
119
+ cs_1.add( Code.new(3, 0, 4) )
120
+ cs_2.add( Code.new(3, 3, 5) )
121
+ expr = Query::AND_NOT.new(cs_1, cs_2)
122
+ result = expr.calculate()
123
+ assert_equal(1, result.num_of_docs)
124
+ assert_equal(3, result.num_of_chars)
125
+ assert_equal(1, result.num_of_passages)
126
+ end
127
+
128
+ def test_or
129
+ cs_1 = CodingTable.new()
130
+ cs_2 = CodingTable.new()
131
+ cs_1.add( Code.new(3, 0, 4) )
132
+ cs_2.add( Code.new(3, 3, 5) )
133
+ expr = Query::OR.new(cs_1, cs_2)
134
+ result = expr.calculate()
135
+ assert_equal(1, result.num_of_docs)
136
+ assert_equal(8, result.num_of_chars)
137
+ assert_equal(1, result.num_of_passages)
138
+ end
139
+ end
@@ -1,31 +1,33 @@
1
- require 'english'
1
+ require 'test-common'
2
2
 
3
- $:.push('../lib/')
4
-
5
- require 'weft/application'
6
- require 'weft/backend'
7
- require 'weft/document'
8
- require 'weft/filters'
3
+ require 'weft'
9
4
 
10
5
  require 'test/unit'
11
6
 
12
7
  class TestFilter < Test::Unit::TestCase
13
- def sample_file(filename)
14
- File.join( File.dirname( __FILE__), 'testdata', filename)
8
+ include QDA
9
+ def test_filter_types()
10
+ import_filters = Filters::import_filters
11
+ assert_kind_of(Hash, import_filters)
12
+ assert_kind_of(Array, import_filters[QDA::Document])
13
+ assert(import_filters[Document].length > 0)
14
+
15
+ export_filters = Filters::export_filters
16
+ assert_kind_of(Hash, export_filters)
17
+ assert_kind_of(Array, export_filters[Document])
15
18
  end
16
-
19
+
17
20
  def test_unix_utf8()
18
- filter = QDA::TextFilter.new()
19
- doc = filter.read(sample_file('text1-unix-utf8.txt'), 'test-unix-utf8')
20
-
21
- str = "This is a text document\nin unix unicode.\n"
22
- assert_equal(str, doc.text, "Document text read in")
21
+ textfile = sample_file('text1-unix-utf8.txt')
22
+ doc = Filters.import_file(Document, textfile) do | doc, filter |
23
+ str = "This is a text document\nin unix unicode.\n"
24
+ assert_equal(str, doc.text, "Document text read in")
25
+ doc.title = 'utf-8'
26
+ end
27
+ assert_equal('utf-8', doc.title)
23
28
  end
24
29
 
25
30
  def test_indexer
26
- idx = QDA::Indexer.new()
27
- idx.index('foo')
28
-
29
31
  widx = QDA::WordIndexer.new()
30
32
  my_word = 'SOMETHING'
31
33
  widx.index(my_word)
@@ -34,34 +36,33 @@ class TestFilter < Test::Unit::TestCase
34
36
  end
35
37
 
36
38
  def test_dos_ascii()
37
- filter = QDA::TextFilter.new()
38
- doc = filter.read(sample_file('text1-dos-ascii.txt'), 'test-ascii')
39
+ text_filter = QDA::Filters.find_import_filter(QDA::Document, 'txt')
40
+ filter = text_filter.new()
41
+ doc = filter.run(sample_file('text1-dos-ascii.txt'))
39
42
 
40
43
  str = "This is a text document\nin dos ascii.\n"
41
44
  assert_equal(str, doc.text, "Document text read in")
42
45
  end
43
46
 
44
47
  def test_pdf
45
- filter = QDA::PDFFilter.new()
46
- windxr = QDA::WordIndexer.new()
47
- filter.add_indexer(windxr)
48
- doc = filter.read('testdata/emacs-refcard-a4.pdf', 'i')
49
-
50
- doc.title = 'Acknowledgments'
51
- word = 'moving'
52
- windxr.words.each do | word, offsets |
53
- offsets.each do | offset |
54
- assert_equal( word, doc[offset, word.length] )
55
- end
56
- end
48
+ doc = Filters.import_file(Document, sample_file('simple.pdf') )
49
+ txt = "This is a simple unlocked PDF document. " <<
50
+ "It should import without problem into Weft QDA.\n\n"
51
+ assert_equal(txt, doc.text)
52
+
53
+ doc = Filters.import_file(Document, sample_file('simple with space.pdf') )
54
+ txt = "This is a simple unlocked PDF document. " <<
55
+ "It should import without problem into Weft QDA.\n\n"
56
+ assert_equal(txt, doc.text, 'OK importing file with space in name')
57
57
  end
58
58
 
59
59
  def test_word_indexing()
60
- filter = QDA::TextFilter.new()
60
+ text_filter = Filters.find_import_filter(Document, 'txt')
61
+ filter = text_filter.new()
62
+
61
63
  windxr = QDA::WordIndexer.new()
62
64
  filter.add_indexer(windxr)
63
- doc = filter.read(sample_file('autocoding-test.txt'),
64
- 'word_indexing')
65
+ doc = filter.run( sample_file('autocoding-test.txt') )
65
66
  # ordinary, capitalised, short, apostrophe, longer
66
67
  test_words = [ 'the', 'Before', 'I', 'It\'s', 'opinions' ]
67
68
  test_words.each do | test_word |
@@ -71,25 +72,36 @@ class TestFilter < Test::Unit::TestCase
71
72
  end
72
73
  end
73
74
 
74
- def test_indexing_iso_8859_1
75
- filter = QDA::TextFilter.new()
76
- windxr = QDA::WordIndexer.new()
75
+ def test_indexing_iso_8859_1()
76
+ text_filter = Filters.find_import_filter(Document, 'txt')
77
+ filter = text_filter.new()
78
+
79
+ windxr = WordIndexer.new()
77
80
  filter.add_indexer(windxr)
78
- doc = filter.read(sample_file('iso-8859-1.txt'), 'iso-8859-1')
81
+
82
+ doc = filter.run( sample_file('iso-8859-1.txt') )
79
83
  word_rx = /[\w\xC0-\xD6\xD8-\xF6\xF8-\xFF][\w\xC0-\xD6\xD8-\xF6\xF8-\xFF\']+/
80
84
  windxr.words.each_key do | word |
81
85
  assert_match(word_rx, word)
82
86
  end
87
+
88
+ windxr2 = WordIndexer.new()
89
+ windxr2.feed(doc)
90
+ windxr.words.each do | word, offsets|
91
+ assert_equal(offsets, windxr2.words[word])
92
+ end
93
+
83
94
  end
84
95
 
85
96
  def test_autocoding
86
- filter = QDA::TextFilter.new()
97
+ text_filter = QDA::Filters.find_import_filter(QDA::Document, 'txt')
98
+ filter = text_filter.new()
99
+
87
100
  autocoder = QDA::AutoCoder.new(/^\*\*(.*)\*\*\s*$/ => 'Heading',
88
101
  /^(.*)\:\s*$/ => 'Speaker')
89
102
  filter.add_indexer(autocoder)
90
103
 
91
- doc = filter.read(sample_file('autocoding-test.txt'),
92
- 'autocoding')
104
+ doc = filter.run( sample_file('autocoding-test.txt') )
93
105
 
94
106
  str = "Before any autocoding\n\nSpeakerA:\nI am the first speaker.\nThis is what I say.\n\n**A TEXT HEADER**\n\nSpeakerB:\nI am the second speaker.\n\nThis is what I say. It's my opinions.\n\nSpeakerA:\nMe again.\n"
95
107
  assert_equal(str, doc.text)
@@ -0,0 +1,113 @@
1
+ require 'test-common'
2
+
3
+ require 'weft'
4
+ require 'tempfile' # so we can test output
5
+
6
+ require 'test/unit'
7
+
8
+ class TestFilter < Test::Unit::TestCase
9
+ include QDA
10
+
11
+ def run_filter(obj, filter)
12
+ tmp = Tempfile.new('output')
13
+ filter.write(obj, tmp)
14
+ tmp.rewind()
15
+ tmp.read()
16
+ end
17
+
18
+ def test_filter_types()
19
+ import_filters = Filters::import_filters
20
+ assert_kind_of(Hash, import_filters)
21
+ assert_kind_of(Array, import_filters[QDA::Document])
22
+ assert(import_filters[Document].length > 0)
23
+
24
+ export_filters = Filters::export_filters
25
+ assert_kind_of(Hash, export_filters)
26
+ assert_kind_of(Array, export_filters[Category])
27
+ assert(export_filters[Category].length > 0)
28
+ assert(export_filters[Document].length > 0)
29
+ assert(export_filters[CodeReview].length > 0)
30
+
31
+ assert( Filters.can_export?(Category) )
32
+ assert( Filters.can_export?(Document) )
33
+ assert( Filters.can_export?(CodeReview) )
34
+ assert( ! Filters.can_export?(Query) )
35
+
36
+ end
37
+
38
+ def test_export_document()
39
+ doc = Document.new('foo')
40
+ doc.append('blah blah blah')
41
+ filter = Filters::DocumentTextOutput.new()
42
+
43
+ tmp = Tempfile.new('doc_text')
44
+ filter.write(doc, tmp)
45
+ tmp.rewind()
46
+ contents = tmp.read()
47
+ # Proper template not written yet
48
+ # assert_match(/blah/m, contents, 'Looks a bit like the document')
49
+ end
50
+
51
+ def test_export_category()
52
+ @app = QDA::Application.new()
53
+ @app.extend(QDA::Backend::SQLite)
54
+ @app.start(:memory => true)
55
+ @app.install_clean()
56
+
57
+ doc = Document.new('My Document')
58
+ doc.append('This is some text in the document')
59
+ @app.save_doc(doc)
60
+
61
+ cat = Category.new('foo & bar')
62
+ cat.code(doc.dbid, 13, 7)
63
+ @app.save_category(cat)
64
+
65
+ contents = run_filter( cat, Filters::CategoryHTMLOutput.new(@app) )
66
+ assert_match(/<html>.*<\/html>/m, contents, "Sort of looks like HTML")
67
+ assert_match(/foo &amp; bar/, contents, "Title's mentioned somewhere")
68
+ assert_match(/foo/, contents, "Category name's mentioned somewhere")
69
+ assert_match(/text in/, contents, "Document text is included")
70
+ end
71
+
72
+ def test_export_codereview_csv()
73
+ @app = QDA::Application.new()
74
+ @app.extend(QDA::Backend::SQLite)
75
+ @app.start(:memory => true)
76
+ @app.install_clean()
77
+ cr = mock_codereview()
78
+ tmp = Tempfile.new('codereview_csv')
79
+
80
+ filter = Filters::CodeReviewCSVOutput.new(@app)
81
+ filter.write(cr, tmp)
82
+ tmp.rewind()
83
+ lines = tmp.read().split("\n")
84
+ assert_match(/foo,bar/, lines[0])
85
+ assert_equal('baz,10,10', lines[1])
86
+ end
87
+
88
+ def mock_codereview()
89
+ cr = CodeReview.new()
90
+ cr.count_method = :num_of_chars
91
+ cat1 = Category.new('foo')
92
+ cat1.code(1, 10, 40)
93
+ cat2 = Category.new('bar')
94
+ cat2.code(1, 70, 20)
95
+ cat3 = Category.new('baz')
96
+ cat3.code(1, 40, 40)
97
+ cat4 = Category.new('qux')
98
+ cat4.code(1, 85, 15)
99
+
100
+ cr.add_col( cat1 )
101
+ cr.add_col( cat2 )
102
+
103
+ cr.add_row( cat3 )
104
+ cr.add_row( cat4 )
105
+ cr
106
+ end
107
+
108
+ def test_export_codereview_html
109
+ cr = mock_codereview()
110
+ contents = run_filter(cr, Filters::CodeReviewHTMLOutput.new() )
111
+ assert_match(/<table/, contents, "There's a table in there somewhere")
112
+ end
113
+ end
@@ -1,8 +1,23 @@
1
- require 'english'
2
- $:.push('../lib/')
3
-
1
+ require 'test-common'
4
2
  require 'weft'
5
- require 'test/unit'
3
+
4
+ class DummyClient
5
+ attr_reader :event_log
6
+ include QDA::Subscriber
7
+
8
+ def initialize(app = nil)
9
+ @event_log = []
10
+ subscribe(app, :all)
11
+ end
12
+
13
+ def reset_log()
14
+ @event_log = []
15
+ end
16
+
17
+ def notify(evt, data)
18
+ event_log.push( :evt => evt, :data => data )
19
+ end
20
+ end
6
21
 
7
22
  class TestSQLiteBasic < Test::Unit::TestCase
8
23
  def sample_file(filename)
@@ -13,17 +28,15 @@ class TestSQLiteBasic < Test::Unit::TestCase
13
28
  @dbfile = nil
14
29
  @app = QDA::Application.new()
15
30
  @app.extend(QDA::Backend::SQLite)
31
+ @client = DummyClient.new(@app)
16
32
  end
17
33
 
18
34
  # delete any files hanging around
19
35
  def teardown()
20
- if @app.started?
21
- # p @app
22
- # @app.end()
23
- if @app.dbfile and File.exist?(@app.dbfile)
24
- File.delete(@app.dbfile)
25
- end
26
- end
36
+ @app.end
37
+ if @app.dbfile and File.exist?(@app.dbfile)
38
+ File.delete(@app.dbfile)
39
+ end
27
40
  end
28
41
 
29
42
  # test save & revert
@@ -33,7 +46,7 @@ class TestSQLiteBasic < Test::Unit::TestCase
33
46
  doc = QDA::Document.new('Doc-1')
34
47
  @app.save_document(doc)
35
48
 
36
- assert_raises(RuntimeError, "Cannot save without a filename") do
49
+ assert_raises(QDA::Backend::BackendError, "Cannot save without filename") do
37
50
  doc = @app.save()
38
51
  end
39
52
 
@@ -78,9 +91,14 @@ class TestSQLiteBasic < Test::Unit::TestCase
78
91
  @app.install_clean()
79
92
  doc = QDA::Document.new('About Something')
80
93
  assert_nil(doc.dbid, "No DBID set")
94
+ assert_nil( @app.doc_exists(doc.title) )
95
+
96
+ # test saving
81
97
  @app.save_document(doc)
82
98
  assert(doc.dbid, 'Got a DBID set')
83
-
99
+ assert_equal( doc.dbid, @app.doc_exists(doc.title) )
100
+
101
+ # test fetching by document identifier
84
102
  fetch_doc = @app.get_doc(doc.dbid)
85
103
  assert(fetch_doc, "Got something back")
86
104
 
@@ -89,6 +107,7 @@ class TestSQLiteBasic < Test::Unit::TestCase
89
107
  assert_equal(doc.title, fetch_doc.title,
90
108
  "Fetched back thing has the same dbid")
91
109
 
110
+ # test fetching by document title
92
111
  fetch_doc = @app.get_doc(doc.title)
93
112
  assert(fetch_doc, "Got something back")
94
113
 
@@ -96,8 +115,25 @@ class TestSQLiteBasic < Test::Unit::TestCase
96
115
  "Fetched back thing has the same dbid")
97
116
  assert_equal(doc.title, fetch_doc.title,
98
117
  "Fetched back thing has the same dbid")
99
- end
100
118
 
119
+ end
120
+ def test_magic_renaming_document()
121
+ @app.start(:dbfile => @dbfile)
122
+ @app.install_clean()
123
+
124
+ @app.save_document(QDA::Document.new('Foo'))
125
+ doc = QDA::Document.new('Foo')
126
+ assert_raises(QDA::NotUniqueNameError) { @app.save_doc(doc) }
127
+ # test duplicate magic renaming
128
+ @app.save_document(doc, true)
129
+ assert(doc.dbid)
130
+ assert_equal('Foo (1)', doc.title)
131
+ doc_1 = QDA::Document.new('Foo')
132
+ @app.save_document(doc_1, true)
133
+ assert(doc_1.dbid)
134
+ assert_equal('Foo (2)', doc_1.title)
135
+ end
136
+
101
137
  def test_save_and_get_document_content()
102
138
  @app.start(:dbfile => @dbfile)
103
139
  @app.install_clean()
@@ -165,6 +201,24 @@ class TestSQLiteBasic < Test::Unit::TestCase
165
201
 
166
202
  end
167
203
 
204
+
205
+ def test_root_category()
206
+ @app.start(:dbfile => @dbfile)
207
+ @app.install_clean()
208
+ root = QDA::Category.new("ROOT", nil, 'the "memo"')
209
+ @app.save_category(root)
210
+ f_root = @app.get_root_category('ROOT')
211
+ assert_equal(nil, f_root.parent)
212
+ assert_equal('ROOT', f_root.name)
213
+ f_root.name = 'RENAMED'
214
+ @app.save_category(f_root)
215
+
216
+ assert_raises(QDA::NotFoundError) { @app.get_root_category('ROOT') }
217
+ f_root = @app.get_root_category('RENAMED')
218
+ assert_equal(nil, f_root.parent)
219
+ assert_equal('RENAMED', f_root.name)
220
+ end
221
+
168
222
  def test_basic_save_category
169
223
  @app.start(:dbfile => @dbfile)
170
224
  @app.install_clean()
@@ -178,19 +232,29 @@ class TestSQLiteBasic < Test::Unit::TestCase
178
232
  "Name retrieved successfully")
179
233
  assert_equal(cat1.memo, f_cat1.memo,
180
234
  "Memo retrieved successfully")
181
-
235
+
236
+ f_cat1 = @app.get_category("/About 'Something'")
237
+ assert_equal(cat1, f_cat1)
238
+
182
239
  # test some parent-child stuff
183
240
  cat2 = QDA::Category.new('Something "Specific"', cat1)
184
241
  @app.save_category(cat2)
185
242
  assert(cat2.dbid, 'Category was assigned a database id')
243
+ assert_equal(cat1, cat2.parent)
244
+
245
+ f_cat1 = @app.get_category(cat1.dbid, true)
246
+ assert_equal(1, f_cat1.children.length)
186
247
 
248
+ f_cat2 = @app.get_category("/About 'Something'/Something")
249
+ assert_equal(cat2, f_cat2)
250
+
251
+
187
252
  cat2a = QDA::Category.new('Something "Specific" & Detailed', cat2)
188
253
  @app.save_category(cat2a)
189
254
 
190
255
  cat3 = QDA::Category.new('Something "Else"', cat1)
191
256
  @app.save_category(cat3)
192
257
 
193
- # @app.dbh.execute("SELECT * FROM category") { | r | p r }
194
258
  f_cat2 = @app.get_category(cat2.dbid)
195
259
  assert_equal(cat2.name, f_cat2.name,
196
260
  "Name retrieved successfully")
@@ -225,8 +289,7 @@ class TestSQLiteBasic < Test::Unit::TestCase
225
289
  assert_equal(QDA::Category, new_root.class)
226
290
  assert_equal("NEw root node", new_root.name)
227
291
  assert_equal(nil, new_root.parent)
228
- assert_raises(RuntimeError) { @app.get_root_category("Doesn't exist") }
229
-
292
+ assert_raises(QDA::NotFoundError) { @app.get_root_category("Doesn't exist") }
230
293
 
231
294
  finds = @app.get_categories_by_path('Something')
232
295
  assert_equal(3, finds.length, 'Normal name/path search')
@@ -244,7 +307,7 @@ class TestSQLiteBasic < Test::Unit::TestCase
244
307
  def test_cut_paste_category
245
308
  @app.start(:dbfile => @dbfile)
246
309
  @app.install_clean()
247
- cat1 = QDA::Category.new("About 'Something'", nil)
310
+ cat1 = QDA::Category.new("Root", nil)
248
311
  @app.save_category(cat1)
249
312
 
250
313
  cat2 = QDA::Category.new('Something "Specific"', cat1)
@@ -256,20 +319,28 @@ class TestSQLiteBasic < Test::Unit::TestCase
256
319
  cat4 = QDA::Category.new('Something "Again"', cat1)
257
320
  @app.save_category(cat4)
258
321
 
259
-
260
322
  cat2.parent = cat3
261
323
  @app.save_category(cat2)
324
+ assert_equal("/Root/Something \"Else\"/Something \"Specific\"",
325
+ cat2.path)
262
326
 
263
-
264
327
  cat4.parent = cat3
265
328
  @app.save_category(cat4)
329
+
266
330
 
331
+ cat4_x = @app.get_category(cat4.dbid)
332
+ assert_equal(cat3, cat4_x.parent)
333
+
267
334
  cat2.parent = cat1
268
335
  @app.save_category(cat2)
269
336
 
270
- deletions = @app.delete_category(cat3)
271
- assert_kind_of(Array, deletions)
272
- assert_equal(2, deletions.length)
337
+ @client.reset_log
338
+ deletion = @app.delete_category(cat3)
339
+ assert_kind_of(QDA::Category, deletion)
340
+ assert_equal(cat3, deletion)
341
+ assert_raises(QDA::NotFoundError) { @app.get_category(cat4.dbid) }
342
+ assert_raises(QDA::NotFoundError) { @app.get_category(cat3.dbid) }
343
+ assert_equal(2, @client.event_log.length)
273
344
  end
274
345
 
275
346
  def test_install()