add unit tests for nested classes

Ben Cornelis 9 anni fa
parent
commit
ac6492f57f
2 ha cambiato i file con 356 aggiunte e 73 eliminazioni
  1. 14 10
      app/models/agents/evernote_agent.rb
  2. 342 63
      spec/models/agents/evernote_agent_spec.rb

+ 14 - 10
app/models/agents/evernote_agent.rb

@@ -40,7 +40,8 @@ module Agents
40 40
             If a note with the above title and notebook did note exist already, one would be created.
41 41
 
42 42
           - When `mode` is `read` the values are search parameters.
43
-            Note: The `content` parameter is not used for searching.
43
+            Note: The `content` parameter is not used for searching. Setting `title` only filters
44
+            notes whose titles contain `title` as a substring, not as the exact title.
44 45
 
45 46
             For example, to find all notes with tag 'CS' in the notebook 'xkcd', use:
46 47
 
@@ -190,9 +191,11 @@ module Agents
190 191
 
191 192
       def create_or_update_note(params)
192 193
         search = Search.new(self, {title: params[:title], notebook: params[:notebook]})
194
+
193 195
         # evernote search can only filter notes with titles containing a substring;
194 196
         # this finds a note with the exact title
195 197
         note = search.notes.detect {|note| note.title == params[:title]}
198
+
196 199
         if note
197 200
           # a note with specified title and notebook exists, so update it
198 201
           update_note(params.merge(guid: note.guid, notebookGuid: note.notebookGuid))
@@ -218,6 +221,7 @@ module Agents
218 221
         params = with_wrapped_content(params)
219 222
 
220 223
         # append specified tags instead of replacing current tags
224
+        # evernote will create any new tags
221 225
         tags = getNoteTagNames(params[:guid])
222 226
         tags.each { |tag|
223 227
           params[:tagNames] << tag unless params[:tagNames].include?(tag) }
@@ -234,7 +238,7 @@ module Agents
234 238
       end
235 239
 
236 240
       def build_note(en_note)
237
-        notebook = find_notebook(guid: en_note.notebookGuid).name
241
+        notebook = find_notebook(guid: en_note.notebookGuid).try(:name)
238 242
         tags = en_note.tagNames || find_tags(en_note.tagGuids.to_a).map(&:name)
239 243
         Note.new(en_note, notebook, tags)
240 244
       end
@@ -276,11 +280,6 @@ module Agents
276 280
           @opts = opts
277 281
         end
278 282
 
279
-        def filtered_metadata
280
-          filter, spec = create_filter, create_spec
281
-          metadata = note_store.findNotesMetadata(filter, 0, 100, spec).notes
282
-        end
283
-
284 283
         def note_guids
285 284
           filtered_metadata.map(&:guid)
286 285
         end
@@ -295,7 +294,7 @@ module Agents
295 294
             # and notes that recently had the specified tags added
296 295
             metadata.select! do |note_data|
297 296
               note_data.updated > opts[:last_checked_at] ||
298
-              (!opts[:notes_with_tags].include?(note_data.guid) && note_data.created > opts[:agent_created_at])
297
+              !opts[:notes_with_tags].include?(note_data.guid)
299 298
             end
300 299
 
301 300
           elsif opts[:last_checked_at]
@@ -306,8 +305,6 @@ module Agents
306 305
           metadata
307 306
         end
308 307
 
309
-        private
310
-
311 308
         def create_filter
312 309
           filter = Evernote::EDAM::NoteStore::NoteFilter.new
313 310
 
@@ -323,6 +320,13 @@ module Agents
323 320
           filter
324 321
         end
325 322
 
323
+        private
324
+
325
+        def filtered_metadata
326
+          filter, spec = create_filter, create_spec
327
+          metadata = note_store.findNotesMetadata(filter, 0, 100, spec).notes
328
+        end
329
+
326 330
         def create_spec
327 331
           Evernote::EDAM::NoteStore::NotesMetadataResultSpec.new(
328 332
             includeTitle: true,

+ 342 - 63
spec/models/agents/evernote_agent_spec.rb

@@ -1,58 +1,59 @@
1 1
 require 'spec_helper'
2 2
 
3 3
 describe Agents::EvernoteAgent do
4
+  class FakeEvernoteNoteStore
5
+    attr_accessor :notes, :tags, :notebooks
6
+    def initialize
7
+      @notes, @tags, @notebooks = [], [], []
8
+    end
4 9
 
5
-  let(:note_store) do
6
-    class FakeEvernoteNoteStore
7
-      attr_accessor :notes, :tags, :notebooks
8
-      def initialize
9
-        @notes, @tags, @notebooks = [], [], []
10
-      end
10
+    def createNote(note)
11
+      note.attributes = OpenStruct.new(source: nil, sourceURL: nil)
12
+      note.guid = @notes.length + 1
13
+      @notes << note
14
+      note
15
+    end
11 16
 
12
-      def createNote(note)
13
-        note.attributes = OpenStruct.new(source: nil, sourceURL: nil)
14
-        note.guid = @notes.length + 1
15
-        @notes << note
16
-        note
17
-      end
17
+    def updateNote(note)
18
+      note.attributes = OpenStruct.new(source: nil, sourceURL: nil)
19
+      old_note = @notes.find {|en_note| en_note.guid == note.guid}
20
+      @notes[@notes.index(old_note)] = note
21
+      note
22
+    end
18 23
 
19
-      def updateNote(note)
20
-        note.attributes = OpenStruct.new(source: nil, sourceURL: nil)
21
-        old_note = @notes.find {|en_note| en_note.guid == note.guid}
22
-        @notes[@notes.index(old_note)] = note
23
-        note
24
-      end
24
+    def getNote(guid, *other_args)
25
+      @notes.find {|note| note.guid == guid}
26
+    end
25 27
 
26
-      def getNote(guid, *other_args)
27
-        @notes.find {|note| note.guid == guid}
28
-      end
28
+    def createNotebook(notebook)
29
+      notebook.guid = @notebooks.length + 1
30
+      @notebooks << notebook
31
+      notebook
32
+    end
29 33
 
30
-      def createNotebook(notebook)
31
-        notebook.guid = @notebooks.length + 1
32
-        @notebooks << notebook
33
-        notebook
34
-      end
34
+    def createTag(tag)
35
+      tag.guid = @tags.length + 1
36
+      @tags << tag
37
+      tag
38
+    end
35 39
 
36
-      def createTag(tag)
37
-        tag.guid = @tags.length + 1
38
-        @tags << tag
39
-        tag
40
-      end
40
+    def listNotebooks; @notebooks; end
41 41
 
42
-      def listNotebooks; @notebooks; end
42
+    def listTags; @tags; end
43 43
 
44
-      def listTags; @tags; end
44
+    def getNoteTagNames(guid)
45
+      getNote(guid).try(:tagNames) || []
46
+    end
45 47
 
46
-      def getNoteTagNames(guid)
47
-        getNote(guid).try(:tagNames) || []
48
-      end
48
+    def findNotesMetadata(*args); end
49
+  end
49 50
 
50
-      def findNotesMetadata(*args); end
51
-    end
51
+  let(:en_note_store) do
52
+    FakeEvernoteNoteStore.new
53
+  end
52 54
 
53
-    note_store = FakeEvernoteNoteStore.new
54
-    stub.any_instance_of(Agents::EvernoteAgent).evernote_note_store { note_store }
55
-    note_store
55
+  before do
56
+    stub.any_instance_of(Agents::EvernoteAgent).evernote_note_store { en_note_store }
56 57
   end
57 58
 
58 59
   describe "#receive" do
@@ -85,18 +86,18 @@ describe Agents::EvernoteAgent do
85 86
 
86 87
         tag1 = OpenStruct.new(name: "funny")
87 88
         tag2 = OpenStruct.new(name: "data")
88
-        [tag1, tag2].each { |tag| note_store.createTag(tag) }
89
+        [tag1, tag2].each { |tag| en_note_store.createTag(tag) }
89 90
       end
90 91
 
91 92
       it "adds a note for any payload it receives" do
92
-        stub(note_store).findNotesMetadata { OpenStruct.new(notes: []) }
93
+        stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
93 94
         Agents::EvernoteAgent.async_receive(@agent.id, [@event.id])
94 95
 
95
-        expect(note_store.notes.size).to eq(1)
96
-        expect(note_store.notes.first.title).to eq("xkcd Survey")
97
-        expect(note_store.notebooks.size).to eq(1)
98
-        expect(note_store.tags.size).to eq(2)
99
-        
96
+        expect(en_note_store.notes.size).to eq(1)
97
+        expect(en_note_store.notes.first.title).to eq("xkcd Survey")
98
+        expect(en_note_store.notebooks.size).to eq(1)
99
+        expect(en_note_store.tags.size).to eq(2)
100
+
100 101
         expect(@agent.events.count).to eq(1)
101 102
         expect(@agent.events.first.payload).to eq({
102 103
           "title" => "xkcd Survey",
@@ -111,18 +112,18 @@ describe Agents::EvernoteAgent do
111 112
         before do
112 113
           note1 = OpenStruct.new(title: "xkcd Survey", notebookGuid: 1)
113 114
           note2 = OpenStruct.new(title: "Footprints", notebookGuid: 1)
114
-          [note1, note2].each { |note| note_store.createNote(note) }
115
-          note_store.createNotebook(OpenStruct.new(name: "xkcd"))
115
+          [note1, note2].each { |note| en_note_store.createNote(note) }
116
+          en_note_store.createNotebook(OpenStruct.new(name: "xkcd"))
116 117
 
117
-          stub(note_store).findNotesMetadata {
118
+          stub(en_note_store).findNotesMetadata {
118 119
             OpenStruct.new(notes: [note1]) }
119 120
         end
120 121
 
121 122
         it "updates the existing note" do
122 123
           Agents::EvernoteAgent.async_receive(@agent.id, [@event.id])
123 124
 
124
-          expect(note_store.notes.size).to eq(2)
125
-          expect(note_store.getNote(1).tagNames).to eq(["funny", "data"])
125
+          expect(en_note_store.notes.size).to eq(2)
126
+          expect(en_note_store.getNote(1).tagNames).to eq(["funny", "data"])
126 127
           expect(@agent.events.count).to eq(1)
127 128
         end
128 129
       end
@@ -134,7 +135,7 @@ describe Agents::EvernoteAgent do
134 135
         end
135 136
 
136 137
         it "creates an event with note content wrapped in ENML" do
137
-          stub(note_store).findNotesMetadata { OpenStruct.new(notes: []) }
138
+          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
138 139
           Agents::EvernoteAgent.async_receive(@agent.id, [@event.id])
139 140
 
140 141
           payload = @agent.events.first.payload
@@ -172,19 +173,19 @@ describe Agents::EvernoteAgent do
172 173
         @checker.save!
173 174
         @checker.created_at = 1.minute.ago
174 175
 
175
-        note_store.createNote(
176
+        en_note_store.createNote(
176 177
           OpenStruct.new(title: "xkcd Survey",
177 178
                          notebookGuid: 1,
178 179
                          updated: 2.minutes.ago.to_i * 1000,
179 180
                          tagNames: ["funny", "comic"])
180 181
         )
181
-        note_store.createNotebook(OpenStruct.new(name: "xkcd"))
182
+        en_note_store.createNotebook(OpenStruct.new(name: "xkcd"))
182 183
         tag1 = OpenStruct.new(name: "funny")
183 184
         tag2 = OpenStruct.new(name: "comic")
184
-        [tag1, tag2].each { |tag| note_store.createTag(tag) }
185
+        [tag1, tag2].each { |tag| en_note_store.createTag(tag) }
185 186
 
186
-        stub(note_store).findNotesMetadata {
187
-          notes = note_store.notes.select do |note|
187
+        stub(en_note_store).findNotesMetadata {
188
+          notes = en_note_store.notes.select do |note|
188 189
             note.notebookGuid == 1 &&
189 190
             %w(funny comic).all? { |tag_name| note.tagNames.include?(tag_name) }
190 191
           end
@@ -203,13 +204,13 @@ describe Agents::EvernoteAgent do
203 204
           expect { @checker.check }.to change { Event.count }.by(0)
204 205
 
205 206
           future_time = (Time.now + 1.minute).to_i * 1000
206
-          note_store.createNote(
207
+          en_note_store.createNote(
207 208
             OpenStruct.new(title: "Footprints",
208 209
                            notebookGuid: 1,
209 210
                            tagNames: ["funny", "comic", "recent"],
210 211
                            updated: future_time))
211 212
 
212
-          note_store.createNote(
213
+          en_note_store.createNote(
213 214
             OpenStruct.new(title: "something else",
214 215
                            notebookGuid: 2,
215 216
                            tagNames: ["funny", "comic"],
@@ -219,7 +220,7 @@ describe Agents::EvernoteAgent do
219 220
         end
220 221
 
221 222
         it "returns notes tagged since the last time it checked" do
222
-          note_store.createNote(
223
+          en_note_store.createNote(
223 224
             OpenStruct.new(title: "Footprints",
224 225
                            notebookGuid: 1,
225 226
                            tagNames: [],
@@ -227,7 +228,7 @@ describe Agents::EvernoteAgent do
227 228
                            updated: Time.now.to_i * 1000))
228 229
           @checker.check
229 230
 
230
-          note_store.getNote(2).tagNames = ["funny", "comic"]
231
+          en_note_store.getNote(2).tagNames = ["funny", "comic"]
231 232
 
232 233
           expect { @checker.check }.to change { Event.count }.by(1)
233 234
         end
@@ -294,4 +295,282 @@ describe Agents::EvernoteAgent do
294 295
       end
295 296
     end
296 297
   end
298
+
299
+  # api wrapper classes
300
+  describe Agents::EvernoteAgent::NoteStore do
301
+    let(:note_store) { Agents::EvernoteAgent::NoteStore.new(en_note_store) }
302
+
303
+    let(:note1) { OpenStruct.new(title: "first note") }
304
+    let(:note2) { OpenStruct.new(title: "second note") }
305
+
306
+    before do
307
+      en_note_store.createNote(note1)
308
+      en_note_store.createNote(note2)
309
+    end
310
+
311
+    describe "#create_note" do
312
+      it "creates a note with given params in evernote note store" do
313
+        note_store.create_note(title: "third note")
314
+
315
+        expect(en_note_store.notes.size).to eq(3)
316
+        expect(en_note_store.notes.last.title).to eq("third note")
317
+      end
318
+
319
+      it "returns a note" do
320
+        expect(note_store.create_note(title: "third note")).to be_a(Agents::EvernoteAgent::Note)
321
+      end
322
+    end
323
+
324
+    describe "#update_note" do
325
+      it "updates an existing note with given params" do
326
+        note_store.update_note(guid: 1, content: "some words")
327
+
328
+        expect(en_note_store.notes.first.content).not_to be_nil
329
+        expect(en_note_store.notes.size).to eq(2)
330
+      end
331
+
332
+      it "returns a note" do
333
+        expect(note_store.update_note(guid: 1, content: "some words")).to be_a(Agents::EvernoteAgent::Note)
334
+      end
335
+    end
336
+
337
+    describe "#find_note" do
338
+      it "gets a note with the given guid" do
339
+        note = note_store.find_note(2)
340
+
341
+        expect(note.title).to eq("second note")
342
+        expect(note).to be_a(Agents::EvernoteAgent::Note)
343
+      end
344
+    end
345
+
346
+    describe "#find_tags" do
347
+      let(:tag1) { OpenStruct.new(name: "tag1") }
348
+      let(:tag2) { OpenStruct.new(name: "tag2") }
349
+      let(:tag3) { OpenStruct.new(name: "tag3") }
350
+
351
+      before do
352
+        [tag1, tag2, tag3].each { |tag| en_note_store.createTag(tag) }
353
+      end
354
+
355
+      it "finds tags with the given guids" do
356
+        expect(note_store.find_tags([1,3])).to eq([tag1, tag3])
357
+      end
358
+    end
359
+
360
+    describe "#find_notebook" do
361
+      let(:notebook1) { OpenStruct.new(name: "notebook1") }
362
+      let(:notebook2) { OpenStruct.new(name: "notebook2") }
363
+
364
+      before do
365
+        [notebook1, notebook2].each {|notebook| en_note_store.createNotebook(notebook)}
366
+      end
367
+
368
+      it "finds a notebook with given name" do
369
+        expect(note_store.find_notebook(name: "notebook1")).to eq(notebook1)
370
+        expect(note_store.find_notebook(name: "notebook3")).to be_nil
371
+      end
372
+
373
+      it "finds a notebook with a given guid" do
374
+        expect(note_store.find_notebook(guid: 2)).to eq(notebook2)
375
+        expect(note_store.find_notebook(guid: 3)).to be_nil
376
+      end
377
+    end
378
+
379
+    describe "#create_or_update_note" do
380
+      let(:notebook1) { OpenStruct.new(name: "first notebook")}
381
+
382
+      before do
383
+        en_note_store.createNotebook(notebook1)
384
+      end
385
+
386
+      context "a note with given title and notebook does not exist" do
387
+        before do
388
+          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
389
+        end
390
+
391
+        it "creates a note" do
392
+          result = note_store.create_or_update_note(title: "third note", notebook: "first notebook")
393
+
394
+          expect(result).to be_a(Agents::EvernoteAgent::Note)
395
+          expect(en_note_store.getNote(3)).to_not be_nil
396
+        end
397
+
398
+        it "also creates the notebook if it does not exist" do
399
+          note_store.create_or_update_note(title: "third note", notebook: "second notebook")
400
+
401
+          expect(note_store.find_notebook(name: "second notebook")).to_not be_nil
402
+        end
403
+      end
404
+
405
+      context "such a note does exist" do
406
+        let(:note) { OpenStruct.new(title: "a note", notebookGuid: 1) }
407
+
408
+        before do
409
+          en_note_store.createNote(note)
410
+          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note]) }
411
+        end
412
+
413
+        it "updates the note" do
414
+          prior_note_count = en_note_store.notes.size
415
+
416
+          result = note_store.create_or_update_note(
417
+            title: "a note", notebook: "first notebook", content: "test content")
418
+
419
+          expect(result).to be_a(Agents::EvernoteAgent::Note)
420
+          expect(en_note_store.notes.size).to eq(prior_note_count)
421
+          expect(en_note_store.getNote(3).content).to include("test content")
422
+        end
423
+      end
424
+    end
425
+  end
426
+
427
+  describe Agents::EvernoteAgent::NoteStore::Search do
428
+    let(:note_store) { Agents::EvernoteAgent::NoteStore.new(en_note_store) }
429
+
430
+    let(:note1) {
431
+      OpenStruct.new(title: "first note", notebookGuid: 1, tagNames: ["funny", "comic"], updated: Time.now) }
432
+    let(:note2) {
433
+      OpenStruct.new(title: "second note", tagNames: ["funny", "comic"], updated: Time.now) }
434
+    let(:note3) {
435
+      OpenStruct.new(title: "third note", notebookGuid: 1, updated: Time.now - 2.minutes) }
436
+
437
+    let(:search) do
438
+      Agents::EvernoteAgent::NoteStore::Search.new(note_store,
439
+        { tagNames: ["funny", "comic"], notebook: "xkcd" })
440
+    end
441
+
442
+    let(:search_with_time) do
443
+      Agents::EvernoteAgent::NoteStore::Search.new(note_store,
444
+        { notebook: "xkcd", last_checked_at: Time.now - 1.minute })
445
+    end
446
+
447
+    let(:search_with_time_and_tags) do
448
+      Agents::EvernoteAgent::NoteStore::Search.new(note_store,
449
+        { notebook: "xkcd", tagNames: ["funny", "comic"], notes_with_tags: [1], last_checked_at: Time.now - 1.minute })
450
+    end
451
+
452
+    before do
453
+      en_note_store.createTag(OpenStruct.new(name: "funny"))
454
+      en_note_store.createTag(OpenStruct.new(name: "comic"))
455
+      en_note_store.createNotebook(OpenStruct.new(name: "xkcd"))
456
+
457
+      [note1, note2, note3].each { |note| en_note_store.createNote(note) }
458
+    end
459
+
460
+    describe "#note_guids" do
461
+      it "returns the guids of notes satisfying search options" do
462
+        stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1]) }
463
+        result = search.note_guids
464
+
465
+        expect(result.size).to eq(1)
466
+        expect(result.first).to eq(1)
467
+      end
468
+    end
469
+
470
+    describe "#notes" do
471
+      context "last_checked_at is not set" do
472
+        it "returns notes satisfying the search options" do
473
+          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1]) }
474
+          result = search.notes
475
+
476
+          expect(result.size).to eq(1)
477
+          expect(result.first.title).to eq("first note")
478
+          expect(result.first).to be_a(Agents::EvernoteAgent::Note)
479
+        end
480
+      end
481
+
482
+      context "last_checked_at is set" do
483
+        context "notes_with_tags is not set" do
484
+          it "only returns notes updated since then" do
485
+            stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1, note3]) }
486
+            result = search_with_time.notes
487
+
488
+            expect(result.size).to eq(1)
489
+            expect(result.first.title).to eq("first note")
490
+          end
491
+        end
492
+
493
+        context "notes_with_tags is set" do
494
+          it "returns notes updated since then or notes with recently added tags" do
495
+            note3.tagNames = ["funny", "comic"]
496
+            stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1, note3]) }
497
+
498
+            result = search_with_time_and_tags.notes
499
+            expect(result.size).to eq(2)
500
+            expect(result.last.title).to eq("third note")
501
+          end
502
+        end
503
+      end
504
+    end
505
+
506
+    describe "#create_filter" do
507
+      it "builds an evernote search filter using search grammar" do
508
+        filter = search.create_filter
509
+        expect(filter.words).to eq("notebook:\"xkcd\" tag:funny tag:comic")
510
+      end
511
+    end
512
+  end
513
+
514
+  describe Agents::EvernoteAgent::Note do
515
+    let(:resource) {
516
+      OpenStruct.new(mime: "image/png",
517
+                     attributes: OpenStruct.new(sourceURL: "http://imgs.xkcd.com/comics/xkcd_survey.png", fileName: "xkcd_survey.png"))
518
+    }
519
+
520
+    let(:en_note_attributes) {
521
+      OpenStruct.new(source: "web.clip", sourceURL: "http://xkcd.com/1572/")
522
+    }
523
+
524
+    let(:en_note) {
525
+      OpenStruct.new(title: "xkcd Survey",
526
+                     tagNames: ["funny", "data"],
527
+                     content: "The xkcd Survey: Big Data for a Big Planet",
528
+                     attributes: en_note_attributes,
529
+                     resources: [resource])
530
+    }
531
+
532
+    describe "#attr" do
533
+      let(:note) {
534
+        Agents::EvernoteAgent::Note.new(en_note, "xkcd", ["funny", "data"])
535
+      }
536
+
537
+      context "when no option is set" do
538
+        it "returns a hash with title, tags, notebook, source and source url" do
539
+          expect(note.attr).to eq(
540
+            {
541
+              title:        en_note.title,
542
+              notebook:     "xkcd",
543
+              tags:         ["funny", "data"],
544
+              source:       en_note.attributes.source,
545
+              source_url:   en_note.attributes.sourceURL
546
+            }
547
+          )
548
+        end
549
+      end
550
+
551
+      context "when include_content is set to true" do
552
+        it "includes content" do
553
+          note_attr = note.attr(include_content: true)
554
+
555
+          expect(note_attr[:content]).to eq(
556
+            "The xkcd Survey: Big Data for a Big Planet"
557
+          )
558
+        end
559
+      end
560
+
561
+      context "when include_resources is set to true" do
562
+        it "includes resources" do
563
+          note_attr = note.attr(include_resources: true)
564
+
565
+          expect(note_attr[:resources].first).to eq(
566
+            {
567
+              url: resource.attributes.sourceURL,
568
+              name:  resource.attributes.fileName,
569
+              mime_type: resource.mime
570
+            }
571
+          )
572
+        end
573
+      end
574
+    end
575
+  end
297 576
 end