1 /*
2 markdown_test.cpp MindForger markdown test
3
4 Copyright (C) 2016-2020 Martin Dvorak <martin.dvorak@mindforger.com>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <cstdlib>
21 #include <iostream>
22 #include <memory>
23 #include <cstdio>
24 #ifndef _WIN32
25 # include <unistd.h>
26 #endif
27
28 #include <gtest/gtest.h>
29
30 #include "../../../src/representations/markdown/markdown_lexem.h"
31 #include "../../../src/representations/markdown/markdown_ast_node.h"
32 #include "../../../src/representations/markdown/markdown_lexer_sections.h"
33 #include "../../../src/representations/markdown/markdown_parser_sections.h"
34 #include "../../../src/representations/markdown/markdown_outline_representation.h"
35
36 #include "../../../src/config/configuration.h"
37 #include "../../../src/mind/ontology/ontology.h"
38 #include "../../../src/mind/ai/autolinking_preprocessor.h"
39 #include "../../../src/persistence/filesystem_persistence.h"
40
41 #include "../test_gear.h"
42
43 using namespace std;
44 using namespace m8r;
45
46 extern char* getMindforgerGitHomePath();
47
TEST(MarkdownParserTestCase,MarkdownLexerSections)48 TEST(MarkdownParserTestCase, MarkdownLexerSections)
49 {
50 unique_ptr<string> fileName
51 = unique_ptr<string>(new string{"/lib/test/resources/basic-repository/memory/outline.md"});
52 fileName.get()->insert(0, getMindforgerGitHomePath());
53 MarkdownLexerSections lexer(fileName.get());
54
55 // minimal MD
56 lexer.tokenize();
57 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
58 printLexems(lexems);
59
60 // asserts
61 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
62
63 EXPECT_EQ(MarkdownLexemType::SECTION, lexems[1]->getType());
64 EXPECT_EQ(0, lexems[1]->getDepth());
65
66 EXPECT_EQ(MarkdownLexemType::WHITESPACES, lexems[2]->getType());
67 EXPECT_EQ(MarkdownLexemType::TEXT, lexems[3]->getType());
68 EXPECT_EQ(0, lexems[3]->getOff());
69 EXPECT_EQ(2, lexems[3]->getIdx());
70 EXPECT_EQ(9, lexems[3]->getLng());
71 }
72
TEST(MarkdownParserTestCase,MarkdownLexerSectionsNoMetadata)73 TEST(MarkdownParserTestCase, MarkdownLexerSectionsNoMetadata)
74 {
75 unique_ptr<string> fileName
76 = unique_ptr<string>(new string{"/lib/test/resources/basic-repository/memory/no-metadata.md"});
77 fileName.get()->insert(0, getMindforgerGitHomePath());
78 MarkdownLexerSections lexer(fileName.get());
79
80 // minimal MD
81 lexer.tokenize();
82 printLexems(lexer.getLexems());
83 }
84
TEST(MarkdownParserTestCase,MarkdownLexerSectionsPreamble)85 TEST(MarkdownParserTestCase, MarkdownLexerSectionsPreamble)
86 {
87 unique_ptr<string> fileName
88 = unique_ptr<string>(new string{"/lib/test/resources/apiary-repository/memory/01. Simplest API.md"});
89 fileName.get()->insert(0, getMindforgerGitHomePath());
90 MarkdownLexerSections lexer(fileName.get());
91
92 // tokenize
93 lexer.tokenize();
94 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
95 printLexems(lexems);
96
97 // asserts
98 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
99 EXPECT_EQ(MarkdownLexemType::LINE, lexems[1]->getType());
100 EXPECT_EQ(MarkdownLexemType::BR, lexems[2]->getType());
101 EXPECT_EQ(MarkdownLexemType::BR, lexems[3]->getType());
102 EXPECT_EQ(MarkdownLexemType::SECTION, lexems[4]->getType());
103 EXPECT_EQ(0, lexems[4]->getDepth());
104 }
105
TEST(MarkdownParserTestCase,MarkdownLexerSectionsPostDeclaredHeaders)106 TEST(MarkdownParserTestCase, MarkdownLexerSectionsPostDeclaredHeaders)
107 {
108 unique_ptr<string> fileName
109 = unique_ptr<string>(new string{"/lib/test/resources/bugs-repository/memory/feature-9-post-declared-headers.md"});
110 fileName.get()->insert(0, getMindforgerGitHomePath());
111 MarkdownLexerSections lexer(fileName.get());
112
113 // tokenize
114 lexer.tokenize();
115 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
116 printLexems(lexems);
117
118 // asserts
119 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
120 EXPECT_EQ(MarkdownLexemType::SECTION_equals, lexems[1]->getType());
121 EXPECT_EQ(MarkdownLexemType::LINE, lexems[2]->getType());
122 EXPECT_EQ(MarkdownLexemType::BR, lexems[3]->getType());
123 EXPECT_EQ(MarkdownLexemType::LINE, lexems[4]->getType());
124 EXPECT_EQ(MarkdownLexemType::BR, lexems[5]->getType());
125 }
126
TEST(MarkdownParserTestCase,MarkdownLexerSectionsPostDeclaredHeaders2)127 TEST(MarkdownParserTestCase, MarkdownLexerSectionsPostDeclaredHeaders2)
128 {
129 string content;
130 content.assign(
131 "Outline Name\n"
132 "========\n"
133 "O text.\n"
134 "\n"
135 "First Section\n"
136 "-------------\n"
137 "N1 text.\n"
138 "\n"
139 "## Second Section\n"
140 "\n"
141 "N2 text.\n"
142 "\n"
143 "Note 3\n"
144 "-------------\n"
145 "N2 text.\n"
146 "\n");
147
148 MarkdownLexerSections lexer(nullptr);
149
150 // tokenize
151 lexer.tokenize(&content);
152 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
153 ASSERT_TRUE(lexems.size());
154 printLexems(lexems);
155
156 // asserts
157 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
158 EXPECT_EQ(MarkdownLexemType::SECTION_equals, lexems[1]->getType());
159 EXPECT_EQ(MarkdownLexemType::LINE, lexems[2]->getType());
160 EXPECT_EQ(MarkdownLexemType::BR, lexems[3]->getType());
161 EXPECT_EQ(MarkdownLexemType::LINE, lexems[4]->getType());
162 EXPECT_EQ(MarkdownLexemType::BR, lexems[5]->getType());
163 }
164
TEST(MarkdownParserTestCase,MarkdownLexerTimeScope)165 TEST(MarkdownParserTestCase, MarkdownLexerTimeScope)
166 {
167 string content;
168 content.assign(
169 "# Outline Name <!-- Metadata: scope: 1y2m3d4h5m; -->\n"
170 "O text.\n"
171 "\n"
172 "## First Section\n"
173 "N1 text.\n"
174 "\n"
175 "## Second Section\n"
176 "N2 text.\n"
177 "\n");
178
179 MarkdownLexerSections lexer(nullptr);
180
181 // tokenize
182 lexer.tokenize(&content);
183 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
184 ASSERT_TRUE(lexems.size());
185 printLexems(lexems);
186
187 // asserts
188 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
189 EXPECT_EQ(MarkdownLexemType::META_PROPERTY_scope, lexems[9]->getType());
190 }
191
TEST(MarkdownParserTestCase,MarkdownLexerLinks)192 TEST(MarkdownParserTestCase, MarkdownLexerLinks)
193 {
194 string content;
195 content.assign(
196 "# Outline Name <!-- Metadata: links: [same as](./o1.md); -->\n"
197 "O text.\n"
198 "\n"
199 "## First Section <!-- Metadata: links: [opposite of](./x.md),[is a](./y.md#a-z); -->\n"
200 "N1 text.\n"
201 "\n"
202 "## Second Section\n"
203 "N2 text.\n"
204 "\n");
205
206 MarkdownLexerSections lexer(nullptr);
207
208 // tokenize
209 lexer.tokenize(&content);
210 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
211 ASSERT_TRUE(lexems.size());
212 printLexems(lexems);
213
214 // asserts
215 EXPECT_EQ(MarkdownLexemType::BEGIN_DOC, lexems[0]->getType());
216 EXPECT_EQ(MarkdownLexemType::META_PROPERTY_links, lexems[9]->getType());
217 }
218
TEST(MarkdownParserTestCase,MarkdownParserSections)219 TEST(MarkdownParserTestCase, MarkdownParserSections)
220 {
221 unique_ptr<string> fileName
222 = unique_ptr<string>(new string{"/lib/test/resources/basic-repository/memory/outline.md"});
223 fileName.get()->insert(0, getMindforgerGitHomePath());
224
225 // minimal MD
226 cout << endl << "- Lexer ----------------------------------------------";
227 MarkdownLexerSections lexer(fileName.get());
228 lexer.tokenize();
229 printLexems(lexer.getLexems());
230 cout << endl << "- Parser ----------------------------------------------";
231 MarkdownParserSections parser(lexer);
232 parser.parse();
233 EXPECT_FALSE(parser.hasMetadata());
234 printAst(parser.getAst());
235 cout << endl << "- DONE ----------------------------------------------";
236 cout << endl;
237 }
238
TEST(MarkdownParserTestCase,MarkdownParserSectionsPreamble)239 TEST(MarkdownParserTestCase, MarkdownParserSectionsPreamble)
240 {
241 unique_ptr<string> fileName
242 = unique_ptr<string>(new string{"/lib/test/resources/apiary-repository/memory/01. Simplest API.md"});
243 fileName.get()->insert(0, getMindforgerGitHomePath());
244
245 // minimal MD
246 cout << endl << "- Lexer ----------------------------------------------";
247 MarkdownLexerSections lexer(fileName.get());
248 lexer.tokenize();
249 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
250 printLexems(lexems);
251 EXPECT_EQ(62, lexems.size());
252
253 cout << endl << "- Parser ----------------------------------------------";
254 MarkdownParserSections parser(lexer);
255 parser.parse();
256 EXPECT_TRUE(!parser.hasMetadata());
257 std::vector<MarkdownAstNodeSection*>* ast = parser.getAst();
258 printAst(ast);
259 EXPECT_EQ(4, ast->size());
260 // preamble section
261 EXPECT_TRUE(ast->at(0)->isPreambleSection());
262 EXPECT_EQ(nullptr, ast->at(0)->getText());
263
264 cout << endl << "- DONE ----------------------------------------------";
265 cout << endl;
266 }
267
TEST(MarkdownParserTestCase,MarkdownParserSectionsEmptyFirstLine)268 TEST(MarkdownParserTestCase, MarkdownParserSectionsEmptyFirstLine)
269 {
270 string repositoryPath{"/tmp"};
271 string fileName{"md-parser-first-empty-line-file.md"};
272 string content;
273 string filePath{repositoryPath+"/"+fileName};
274
275 content.assign(
276 "\n"
277 "\n"
278 "\n"
279 "# First Markdown"
280 "\nFirst MD text."
281 "\n"
282 "\n## Note 1"
283 "\nNote 1 text."
284 "\n"
285 "\n## Note 2"
286 "\nNote 2 text."
287 "\n");
288 m8r::stringToFile(filePath, content);
289
290 // minimal MD
291 cout << endl << "- Lexer ----------------------------------------------";
292 MarkdownLexerSections lexer(&filePath);
293 lexer.tokenize();
294 const std::vector<MarkdownLexem*>& lexems = lexer.getLexems();
295 printLexems(lexems);
296 EXPECT_EQ(31, lexems.size());
297
298 cout << endl << "- Parser ----------------------------------------------";
299 MarkdownParserSections parser(lexer);
300 parser.parse();
301 EXPECT_TRUE(!parser.hasMetadata());
302 std::vector<MarkdownAstNodeSection*>* ast = parser.getAst();
303 printAst(ast);
304 EXPECT_EQ(4, ast->size());
305 // preamble section
306 EXPECT_TRUE(ast->at(0)->isPreambleSection());
307 EXPECT_EQ(nullptr, ast->at(0)->getText());
308
309 cout << endl << "- DONE ----------------------------------------------";
310 cout << endl;
311 }
312
TEST(MarkdownParserTestCase,MarkdownParserSectionsNoMetadata)313 TEST(MarkdownParserTestCase, MarkdownParserSectionsNoMetadata)
314 {
315 unique_ptr<string> fileName
316 = unique_ptr<string>(new string{"/lib/test/resources/basic-repository/memory/no-metadata.md"});
317 fileName.get()->insert(0, getMindforgerGitHomePath());
318
319 // minimal MD
320 cout << endl << "- Lexer ----------------------------------------------";
321 MarkdownLexerSections lexer(fileName.get());
322 lexer.tokenize();
323 printLexems(lexer.getLexems());
324 cout << endl << "- Parser ----------------------------------------------";
325 MarkdownParserSections parser(lexer);
326 parser.parse();
327 EXPECT_TRUE(!parser.hasMetadata());
328 printAst(parser.getAst());
329 cout << endl << "- DONE ----------------------------------------------";
330 cout << endl;
331 }
332
TEST(MarkdownParserTestCase,Bug37Meta)333 TEST(MarkdownParserTestCase, Bug37Meta)
334 {
335 string fileName{"/lib/test/resources/bugs-repository/memory/bug-37-meta.md"};
336 fileName.insert(0, getMindforgerGitHomePath());
337 cout << endl << "- Lexer ----------------------------------------------";
338 MarkdownLexerSections lexer(&fileName);
339 lexer.tokenize();
340 printLexems(lexer.getLexems());
341 cout << endl << "- Parser ----------------------------------------------";
342 MarkdownParserSections parser(lexer);
343 parser.parse();
344 EXPECT_TRUE(parser.hasMetadata());
345 printAst(parser.getAst());
346 ASSERT_EQ(4, parser.getAst()->size());
347 cout << endl << "- DONE ----------------------------------------------";
348 cout << endl;
349 }
350
TEST(MarkdownParserTestCase,Bug37Nometa)351 TEST(MarkdownParserTestCase, Bug37Nometa)
352 {
353 string fileName{"/lib/test/resources/bugs-repository/memory/bug-37-nometa.md"};
354 fileName.insert(0, getMindforgerGitHomePath());
355 cout << endl << "- Lexer ----------------------------------------------";
356 MarkdownLexerSections lexer(&fileName);
357 lexer.tokenize();
358 printLexems(lexer.getLexems());
359 cout << endl << "- Parser ----------------------------------------------";
360 MarkdownParserSections parser(lexer);
361 parser.parse();
362 EXPECT_FALSE(parser.hasMetadata());
363 printAst(parser.getAst());
364 ASSERT_EQ(4, parser.getAst()->size());
365 cout << endl << "- DONE ----------------------------------------------";
366 cout << endl;
367 }
368
TEST(MarkdownParserTestCase,Bug37Notrailing)369 TEST(MarkdownParserTestCase, Bug37Notrailing)
370 {
371 string fileName{"/lib/test/resources/bugs-repository/memory/bug-37-notrailing.md"};
372 fileName.insert(0, getMindforgerGitHomePath());
373 cout << endl << "- Lexer ----------------------------------------------";
374 MarkdownLexerSections lexer(&fileName);
375 lexer.tokenize();
376 printLexems(lexer.getLexems());
377 cout << endl << "- Parser ----------------------------------------------";
378 MarkdownParserSections parser(lexer);
379 parser.parse();
380 EXPECT_FALSE(parser.hasMetadata());
381 printAst(parser.getAst());
382 ASSERT_EQ(4, parser.getAst()->size());
383 cout << endl << "- DONE ----------------------------------------------";
384 cout << endl;
385 }
386
TEST(MarkdownParserTestCase,MarkdownRepresentation)387 TEST(MarkdownParserTestCase, MarkdownRepresentation)
388 {
389 string repositoryPath{"/lib/test/resources/basic-repository"};
390 repositoryPath.insert(0, getMindforgerGitHomePath());
391
392 m8r::Configuration& config = m8r::Configuration::getInstance();
393 config.clear();
394 config.setConfigFilePath("/tmp/cfg-mptc-mr.md");
395 config.setActiveRepository(config.addRepository(m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath)));
396
397 m8r::Ontology ontology{};
398
399 string text =
400 "## Canonical Message <!-- Metadata: tags: important; type: Goal; created: 2015-05-02 21:30:28; reads: 55; read: 2016-03-31 13:54:45; revision: 3; modified: 2016-03-31 13:54:45; importance: 3/5; urgency: 2/5; progress: 20%; -->\n"
401 "\n"
402 "This document contains ideas related to the definition of similarity codes for canonical messages.\n"
403 "\n";
404
405 cout << endl << "- MD > Note ----------------------------------------------";
406 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
407
408 unique_ptr<Note> note = unique_ptr<Note>(mdr.note(&text));
409 if(note) {
410 cout << endl << " '" << note->getName() << "' (name)";
411 cout << endl << " '" << note->getDepth() << "' (depth)";
412 cout << endl << " " << (note->getPrimaryTag()?note->getPrimaryTag()->getName():"NULL") << " (primary tag)";
413 if(note->getTags()->size()) {
414 for(size_t t=0; t<note->getTags()->size(); t++) {
415 cout << endl << " " << (*note->getTags())[t]->getName() << " (tag)";
416 }
417 }
418 cout << endl << " " << (note->getType()?note->getType()->getName():"NULL") << " (type)";
419 cout << endl << " Description[" << note->getDescription().size() << "]:";
420 for(string* description:note->getDescription()) {
421 cout << endl << " '" << *description << "' (description)";
422 }
423 cout << endl << " " << note->getCreated() << " (created)";
424 cout << endl << " " << note->getModified() << " (modified)";
425 cout << endl << " " << note->getRevision() << " (revision)";
426 cout << endl << " " << note->getReads() << " (reads)";
427 cout << endl << " " << note->getRead() << " (read)";
428 } else {
429 cout << endl << "Note is NULL!";
430 }
431
432 cout << endl << "- DONE ----------------------------------------------";
433 }
434
TEST(MarkdownParserTestCase,MarkdownRepresentationPreamble)435 TEST(MarkdownParserTestCase, MarkdownRepresentationPreamble)
436 {
437 string repositoryPath{"/lib/test/resources/apiary-repository"};
438 repositoryPath.insert(0, getMindforgerGitHomePath());
439 m8r::Configuration& config = m8r::Configuration::getInstance();
440 config.clear();
441 config.setConfigFilePath("/tmp/cfg-mptc-mrp.md");
442 config.setActiveRepository(config.addRepository(m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath)));
443 m8r::Ontology ontology{};
444
445 // parse
446 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
447 unique_ptr<string> fileName
448 = unique_ptr<string>(new string{"/lib/test/resources/apiary-repository/memory/01. Simplest API.md"});
449 fileName.get()->insert(0, getMindforgerGitHomePath());
450 File file{*fileName.get()};
451 m8r::Outline* o = mdr.outline(file);
452
453 // asserts
454 EXPECT_NE(nullptr, o);
455 EXPECT_EQ(2, o->getNotesCount());
456
457 cout << endl << "- Preamble ---";
458 EXPECT_EQ(2, o->getPreamble().size());
459 cout << endl << "'" << *(o->getPreamble()[0]) << "'";
460 cout << endl << "'" << *(o->getPreamble()[1]) << "'";
461 EXPECT_EQ("FORMAT: 1A", *(o->getPreamble()[0]));
462 EXPECT_EQ("", *(o->getPreamble()[1]));
463 EXPECT_TRUE(o->isApiaryBlueprint());
464
465 cout << endl << "- Outline ---";
466 cout << endl << "'" << o->getName() << "'";
467 EXPECT_EQ("The Simplest API", o->getName());
468 EXPECT_EQ(15, o->getDescription().size());
469
470 cout << endl << "- N[0] ---";
471 cout << endl << "'" << o->getNotes()[0]->getName() << "'";
472 EXPECT_EQ("API Blueprint", o->getNotes()[0]->getName());
473 EXPECT_EQ(3, o->getNotes()[0]->getDescription().size());
474
475 cout << endl << "- N[1] ---";
476 cout << endl << "'" << o->getNotes()[1]->getName() << "'";
477 EXPECT_EQ("GET /message", o->getNotes()[1]->getName());
478
479 // preamble serialization check
480 string* original = m8r::fileToString(o->getKey());
481 string* serialized = mdr.to(o);
482 EXPECT_EQ(*original, *serialized);
483
484 delete original;
485 delete serialized;
486 delete o;
487 cout << endl << "- DONE ----------------------------------------------" << endl;
488 }
489
TEST(MarkdownParserTestCase,MarkdownRepresentationPostDeclaredSection)490 TEST(MarkdownParserTestCase, MarkdownRepresentationPostDeclaredSection)
491 {
492 string repositoryPath{"/tmp"};
493 string fileName{"md-post-declared-section.md"};
494 string content;
495 string filePath{repositoryPath+"/"+fileName};
496
497 content.assign(
498 "Outline Name\n"
499 "============\n"
500 "O text.\n"
501 "\n"
502 "First Section\n"
503 "-------------\n"
504 "N1 text.\n"
505 "\n"
506 "## Second Section\n"
507 "\n"
508 "N2 text.\n"
509 "\n"
510 "Note 2\n"
511 "------\n"
512 "\n"
513 "N2 text.\n"
514 "\n"
515 "Note 3\n"
516 "------\n"
517 "N3 text.\n"
518 "\n");
519 m8r::stringToFile(filePath, content);
520
521 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
522 repository->setMode(m8r::Repository::RepositoryMode::FILE);
523 repository->setFile(fileName);
524 m8r::Configuration& config = m8r::Configuration::getInstance();
525 config.clear();
526 config.setConfigFilePath("/tmp/cfg-mptc-mrpdc.md");
527 config.setActiveRepository(config.addRepository(repository));
528 m8r::Ontology ontology{};
529
530 // parse
531 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
532 File file{filePath};
533 m8r::Outline* o = mdr.outline(file);
534
535 // asserts
536 EXPECT_NE(nullptr, o);
537 ASSERT_EQ(4, o->getNotesCount());
538
539 cout << endl << "- O ---";
540 cout << endl << "Name: '" << o->getName() << "'";
541 EXPECT_EQ("Outline Name", o->getName());
542 cout << endl << "Desc: '" << o->getDescriptionAsString() << "'";
543 EXPECT_EQ(2, o->getDescription().size());
544
545 EXPECT_EQ("First Section", o->getNotes()[0]->getName());
546 EXPECT_EQ(2, o->getNotes()[0]->getDescription().size());
547 EXPECT_EQ("Second Section", o->getNotes()[1]->getName());
548 EXPECT_EQ(3, o->getNotes()[1]->getDescription().size());
549 EXPECT_EQ("Note 2", o->getNotes()[2]->getName());
550 EXPECT_EQ(3, o->getNotes()[2]->getDescription().size());
551 EXPECT_EQ("Note 3", o->getNotes()[3]->getName());
552 EXPECT_EQ(2, o->getNotes()[3]->getDescription().size());
553
554 // serialize
555 string* serialized = mdr.to(o);
556 cout << endl << "- SERIALIZED ---";
557 cout << endl << *serialized;
558 EXPECT_EQ(content, *serialized);
559
560 delete serialized;
561 delete o;
562 }
563
TEST(MarkdownParserTestCase,MarkdownRepresentationTrailingHashesSection)564 TEST(MarkdownParserTestCase, MarkdownRepresentationTrailingHashesSection)
565 {
566 string repositoryPath{"/tmp"};
567 string fileName{"md-trailing-hashes-section.md"};
568 string content;
569 string filePath{repositoryPath+"/"+fileName};
570
571 content.assign(
572 "# Outline Name #\n"
573 "O text.\n"
574 "\n"
575 "# First Section #\n"
576 "N1 text.\n"
577 "\n"
578 "# WRONG 1 ##\n"
579 "W1 text.\n"
580 "\n"
581 "## Second Section ##\n"
582 "N2 text.\n"
583 "\n"
584 "## WRONG 2 #\n"
585 "W2 text.\n"
586 "\n"
587 "### Note 3 ###\n"
588 "N3 text.\n"
589 "\n");
590 m8r::stringToFile(filePath, content);
591
592 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
593 repository->setMode(m8r::Repository::RepositoryMode::FILE);
594 repository->setFile(fileName);
595 m8r::Configuration& config = m8r::Configuration::getInstance();
596 config.clear();
597 config.setConfigFilePath("/tmp/cfg-mptc-mrthc.md");
598 config.setActiveRepository(config.addRepository(repository));
599 m8r::Ontology ontology{};
600
601 // parse
602 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
603 File file{filePath};
604 m8r::Outline* o = mdr.outline(file);
605
606 // asserts
607 EXPECT_NE(nullptr, o);
608 ASSERT_EQ(5, o->getNotesCount());
609
610 cout << endl << "- O ---";
611 cout << endl << "Name: '" << o->getName() << "'";
612 EXPECT_EQ("Outline Name", o->getName());
613 cout << endl << "Desc: '" << o->getDescriptionAsString() << "'";
614 EXPECT_EQ(false, o->isPostDeclaredSection());
615 EXPECT_EQ(true, o->isTrailingHashesSection());
616
617 EXPECT_EQ("First Section", o->getNotes()[0]->getName());
618 EXPECT_EQ(false, o->getNotes()[0]->isPostDeclaredSection());
619 EXPECT_EQ(true, o->getNotes()[0]->isTrailingHashesSection());
620 EXPECT_EQ(2, o->getNotes()[0]->getDescription().size());
621
622 EXPECT_EQ("WRONG 1 ##", o->getNotes()[1]->getName());
623 EXPECT_EQ(false, o->getNotes()[1]->isPostDeclaredSection());
624 EXPECT_EQ(false, o->getNotes()[1]->isTrailingHashesSection());
625 EXPECT_EQ(2, o->getNotes()[1]->getDescription().size());
626
627 EXPECT_EQ("Second Section", o->getNotes()[2]->getName());
628 EXPECT_EQ(false, o->getNotes()[2]->isPostDeclaredSection());
629 EXPECT_EQ(true, o->getNotes()[2]->isTrailingHashesSection());
630 EXPECT_EQ(2, o->getNotes()[2]->getDescription().size());
631
632 EXPECT_EQ("WRONG 2 #", o->getNotes()[3]->getName());
633 EXPECT_EQ(false, o->getNotes()[3]->isPostDeclaredSection());
634 EXPECT_EQ(false, o->getNotes()[3]->isTrailingHashesSection());
635 EXPECT_EQ(2, o->getNotes()[3]->getDescription().size());
636
637 EXPECT_EQ("Note 3", o->getNotes()[4]->getName());
638 EXPECT_EQ(false, o->getNotes()[4]->isPostDeclaredSection());
639 EXPECT_EQ(true, o->getNotes()[4]->isTrailingHashesSection());
640 EXPECT_EQ(2, o->getNotes()[4]->getDescription().size());
641
642 // serialize
643 string* serialized = mdr.to(o);
644 cout << endl << "- SERIALIZED ---";
645 cout << endl << *serialized;
646 EXPECT_EQ(content, *serialized);
647
648 delete serialized;
649 delete o;
650 }
651
TEST(MarkdownParserTestCase,MarkdownRepresentationEmptyFirstLine)652 TEST(MarkdownParserTestCase, MarkdownRepresentationEmptyFirstLine)
653 {
654 string repositoryPath{"/tmp"};
655 string fileName{"md-parser-first-empty-line-file.md"};
656 string content;
657 string filePath{repositoryPath+"/"+fileName};
658
659 content.assign(
660 "\n"
661 "\n"
662 "\n"
663 "# First Markdown"
664 "\nFirst MD text."
665 "\n"
666 "\n## Note 1"
667 "\nNote 1 text."
668 "\n"
669 "\n## Note 2"
670 "\nNote 2 text."
671 "\n");
672 m8r::stringToFile(filePath, content);
673
674 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
675 repository->setMode(m8r::Repository::RepositoryMode::FILE);
676 repository->setFile(fileName);
677 m8r::Configuration& config = m8r::Configuration::getInstance();
678 config.clear();
679 config.setConfigFilePath("/tmp/cfg-mptc-mrefl.md");
680 config.setActiveRepository(config.addRepository(repository));
681 m8r::Ontology ontology{};
682
683 // parse
684 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
685 File file{filePath};
686 m8r::Outline* o = mdr.outline(file);
687
688 // asserts
689 EXPECT_NE(nullptr, o);
690 EXPECT_EQ(2, o->getNotesCount());
691
692 cout << endl << "- Preamble ---";
693 EXPECT_EQ(3, o->getPreamble().size());
694 cout << endl << "'" << *(o->getPreamble()[0]) << "'";
695 cout << endl << "'" << *(o->getPreamble()[1]) << "'";
696 cout << endl << "'" << *(o->getPreamble()[2]) << "'";
697 EXPECT_EQ("", *(o->getPreamble()[0]));
698 EXPECT_EQ("", *(o->getPreamble()[1]));
699 EXPECT_EQ("", *(o->getPreamble()[2]));
700 EXPECT_TRUE(!o->isApiaryBlueprint());
701
702 cout << endl << "- Outline ---";
703 cout << endl << "'" << o->getName() << "'";
704 EXPECT_EQ("First Markdown", o->getName());
705 EXPECT_EQ(2, o->getDescription().size());
706
707 delete o;
708 }
709
TEST(MarkdownParserTestCase,FileSystemPersistence)710 TEST(MarkdownParserTestCase, FileSystemPersistence)
711 {
712 string repositoryPath{"/lib/test/resources/basic-repository"};
713 repositoryPath.insert(0, getMindforgerGitHomePath());
714
715 m8r::Configuration& config = m8r::Configuration::getInstance();
716 config.clear();
717 config.setConfigFilePath("/tmp/cfg-mptc-fsp.md");
718 config.setActiveRepository(config.addRepository(m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath)));
719 m8r::Ontology ontology{};
720 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
721 m8r::HtmlOutlineRepresentation htmlr{ontology, nullptr};
722 m8r::FilesystemPersistence persistence{mdr, htmlr};
723
724 unique_ptr<string> text = unique_ptr<string>(new string{"abc"});
725 cout << persistence.createFileName(string("/tmp"), text.get(), string(FILE_EXTENSION_MD_MD));
726 }
727
TEST(MarkdownParserBugsTestCase,EmptyNameSkipsEof)728 TEST(MarkdownParserBugsTestCase, EmptyNameSkipsEof)
729 {
730 string repositoryPath{"/lib/test/resources/bugs-repository"};
731 repositoryPath.insert(0, getMindforgerGitHomePath());
732
733 m8r::Configuration& config = m8r::Configuration::getInstance();
734 config.clear();
735 config.setConfigFilePath("/tmp/cfg-mptc-ense.md");
736 config.setActiveRepository(config.addRepository(m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath)));
737 m8r::Ontology ontology{};
738
739 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
740 string outlineFilename{"/lib/test/resources/bugs-repository/memory/bug-37.md"};
741 outlineFilename.insert(0, getMindforgerGitHomePath());
742 m8r::Outline* o = mdr.outline(outlineFilename);
743 string* s = mdr.to(o);
744
745 cout << endl << "-----------------------------------------------";
746 cout << *s;
747 cout << endl << "-----------------------------------------------";
748
749 // TODO asserts
750
751 std::ofstream out("./tests/resources/bugs-repository/memory/bug-37-PARSER-OUTPUT.md");
752 out << *s;
753 out.close();
754
755 delete o;
756 delete s;
757
758 cout << endl << "- DONE ----------------------------------------------";
759 }
760
TEST(MarkdownParserTestCase,TimeScope)761 TEST(MarkdownParserTestCase, TimeScope)
762 {
763 string repositoryPath{"/tmp"};
764 string fileName{"md-parser-time-scope.md"};
765 string content;
766 string filePath{repositoryPath+"/"+fileName};
767
768 content.assign(
769 "# Outline Name <!-- Metadata: scope: 1y2m3d4h5m; -->\n"
770 "O text.\n"
771 "\n"
772 "## First Section\n"
773 "N1 text.\n"
774 "\n"
775 "## Second Section\n"
776 "N2 text.\n"
777 "\n");
778 m8r::stringToFile(filePath, content);
779
780 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
781 repository->setMode(m8r::Repository::RepositoryMode::FILE);
782 repository->setFile(fileName);
783 m8r::Configuration& config = m8r::Configuration::getInstance();
784 config.clear();
785 config.setConfigFilePath("/tmp/cfg-mptc-ts.md");
786 config.setActiveRepository(config.addRepository(repository));
787 m8r::Ontology ontology{};
788
789 // parse
790 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
791 File file{filePath};
792 m8r::Outline* o = mdr.outline(file);
793
794 // asserts
795 EXPECT_NE(nullptr, o);
796 string timeScopeAsString{};
797 o->getTimeScope().toString(timeScopeAsString);
798 cout << endl << "Time scope: " << timeScopeAsString << " (" << o->getTimeScope().relativeSecs << "s)";
799 EXPECT_EQ(36993900, o->getTimeScope().relativeSecs);
800 o->getTimeScope().toString(timeScopeAsString);
801 EXPECT_EQ("1y2m3d4h5m", timeScopeAsString);
802 EXPECT_EQ(2, o->getNotesCount());
803
804 // serialize
805 string* serialized = mdr.to(o);
806 cout << endl << "- SERIALIZED ---";
807 cout << endl << *serialized;
808 EXPECT_NE(std::string::npos, serialized->find("scope: 1y2m3d4h5m;"));
809
810 delete serialized;
811 delete o;
812 }
813
TEST(MarkdownParserTestCase,Deadline)814 TEST(MarkdownParserTestCase, Deadline)
815 {
816 string repositoryPath{"/tmp"};
817 string fileName{"md-parser-deadline.md"};
818 string content;
819 string filePath{repositoryPath+"/"+fileName};
820
821 content.assign(
822 "# Outline Name\n"
823 "O text.\n"
824 "\n"
825 "## First Section <!-- Metadata: deadline: 2010-11-12 13:14:15; -->\n"
826 "N1 text.\n"
827 "\n"
828 "## Second Section\n"
829 "N2 text.\n"
830 "\n");
831 m8r::stringToFile(filePath, content);
832
833 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
834 repository->setMode(m8r::Repository::RepositoryMode::FILE);
835 repository->setFile(fileName);
836 m8r::Configuration& config = m8r::Configuration::getInstance();
837 config.clear();
838 config.setConfigFilePath("/tmp/cfg-mptc-d.md");
839 config.setActiveRepository(config.addRepository(repository));
840 m8r::Ontology ontology{};
841
842 // parse
843 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
844 File file{filePath};
845 m8r::Outline* o = mdr.outline(file);
846
847 // asserts
848 EXPECT_NE(nullptr, o);
849 EXPECT_EQ(2, o->getNotesCount());
850
851 cout << endl << "Deadline: " << o->getNotes()[0]->getDeadline();
852 #ifdef _WIN32
853 tm deadLineDate = { 15,14,13,12,10,110, 0, 0, 0 };
854 #else
855 tm deadLineDate = { 15,14,13,12,10,110, 0, 0, 0, 0, 0 };
856 #endif // _WIN32
857 time_t deadLine = mktime(&deadLineDate);
858 EXPECT_EQ(deadLine, o->getNotes()[0]->getDeadline());
859
860 // serialize
861 string* serialized = mdr.to(o);
862 cout << endl << "- SERIALIZED ---";
863 cout << endl << *serialized;
864 EXPECT_NE(std::string::npos, serialized->find("deadline: 2010-11-12 13:14:15"));
865
866 delete serialized;
867 delete o;
868 }
869
TEST(MarkdownParserTestCase,Links)870 TEST(MarkdownParserTestCase, Links)
871 {
872 string repositoryPath{"/tmp"};
873 string fileName{"md-parser-deadline.md"};
874 string content;
875 string filePath{repositoryPath+"/"+fileName};
876
877 content.assign(
878 "# Outline Name <!-- Metadata: links: [same as](./o1.md); -->\n"
879 "O text.\n"
880 "\n"
881 "## First Section <!-- Metadata: links: [opposite of](./x.md),[is a](./y.md#a-z); -->\n"
882 "N1 text.\n"
883 "\n"
884 "## Second Section\n"
885 "N2 text.\n"
886 "\n");
887 m8r::stringToFile(filePath, content);
888
889 m8r::Repository* repository = m8r::RepositoryIndexer::getRepositoryForPath(repositoryPath);
890 repository->setMode(m8r::Repository::RepositoryMode::FILE);
891 repository->setFile(fileName);
892 m8r::Configuration& config = m8r::Configuration::getInstance();
893 config.clear();
894 config.setConfigFilePath("/tmp/cfg-mptc-l.md");
895 config.setActiveRepository(config.addRepository(repository));
896 m8r::Ontology ontology{};
897
898 // parse
899 m8r::MarkdownOutlineRepresentation mdr{ontology, nullptr};
900 File file{filePath};
901 m8r::Outline* o = mdr.outline(file);
902
903 // asserts
904 EXPECT_NE(nullptr, o);
905 EXPECT_EQ(2, o->getNotesCount());
906
907 cout << endl << "O links: " << o->getLinksCount();
908 EXPECT_EQ(1, o->getLinksCount());
909
910 cout << endl << "N links: " << o->getNotes()[0]->getLinksCount();
911 EXPECT_EQ(2, o->getNotes()[0]->getLinksCount());
912
913 // serialize
914 string* serialized = mdr.to(o);
915 cout << endl << "- SERIALIZED ---";
916 cout << endl << *serialized;
917 EXPECT_NE(std::string::npos, serialized->find("[same as](./o1.md)"));
918 EXPECT_NE(std::string::npos, serialized->find("[opposite of](./x.md)"));
919 EXPECT_NE(std::string::npos, serialized->find("[is a](./y.md#a-z)"));
920
921 delete serialized;
922 delete o;
923 }
924
TEST(MarkdownParserTestCase,Bug622Loop64kLinesOverflow)925 TEST(MarkdownParserTestCase, Bug622Loop64kLinesOverflow)
926 {
927 string fileName{"/lib/test/resources/bugs-repository/memory/bug-622-70k-lines.md"};
928 fileName.insert(0, getMindforgerGitHomePath());
929 cout << endl << "- Lexer ----------------------------------------------";
930 MarkdownLexerSections lexer(&fileName);
931 lexer.tokenize();
932 // file too big - do NOT print: printLexems(lexer.getLexems());
933 cout << endl << "- Parser ----------------------------------------------";
934 MarkdownParserSections parser(lexer);
935 parser.parse();
936 // file too big - do NOT print: printAst(parser.getAst());
937 ASSERT_EQ(71234, parser.getAst()->size());
938 cout << endl << "- DONE ----------------------------------------------";
939 cout << endl;
940 }
941