def test_invalid_metadata_block_end(self):
        """Check if the metadata block end is wrong."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "no_metadata_end.md")

        # Metadata blocks should end with '___' or '...' if not it should fail
        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Could not find end of metadata block.", message)
    def test_empty_file(self):
        """Check if a file is empty."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "empty.md")

        # If the file is empty retrieval of metadata should fail
        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Could not find metadata. File is empty.", message)
    def test_non_empty_file_no_metadata(self):
        """Check if a file has no metadata."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "no_metadata.md")

        # If the file is not empty but has no metadata it should fail
        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Could not find metadata header '---'.", message)
    def test_invalid_self_contained_argument(self):
        """Check that specifying --self-contained raises an exception."""
        pandoc_arguments = ["--self-contained"]
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS, PANDOC_ARGS=pandoc_arguments
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Argument --self-contained is not supported.", message)
    def test_metadata_block_end_with_leading_spaces(self):
        """Check if metadata block ending with leading spaces throws an exception."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "metadata_end_with_leading_spaces.md")

        # Metadata end --- or ... should not have leading spaces
        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Could not find end of metadata block.", message)
    def read(self, filename):
        """Parse content and metadata of markdown files"""
        QUIET = self.settings.get('RMD_READER_KNITR_QUIET', True)
        ENCODING = self.settings.get('RMD_READER_KNITR_ENCODING', 'UTF-8')
        CLEANUP = self.settings.get('RMD_READER_CLEANUP', True)
        RENAME_PLOT = self.settings.get('RMD_READER_RENAME_PLOT', 'chunklabel')
        site_url = self.settings.get('SITEURL', '')
        if type(RENAME_PLOT) is bool:
            logger.error(
                "RMD_READER_RENAME_PLOT takes a string value (either chunklabel or directory), please see the readme."
            )
            if RENAME_PLOT:
                RENAME_PLOT = 'chunklabel'
                logger.error("Defaulting to chunklabel")
            else:
                RENAME_PLOT = 'disabled'
                logger.error("Disabling plot renaming")
        logger.debug("RMD_READER_KNITR_QUIET = %s", QUIET)
        logger.debug("RMD_READER_KNITR_ENCODING = %s", ENCODING)
        logger.debug("RMD_READER_CLEANUP = %s", CLEANUP)
        logger.debug("RMD_READER_RENAME_PLOT = %s", RENAME_PLOT)
        # replace single backslashes with double backslashes
        filename = filename.replace('\\', '\\\\')
        # parse Rmd file - generate md file
        md_filename = filename.replace('.Rmd', '.aux').replace('.rmd', '.aux')
        if RENAME_PLOT == 'chunklabel' or RENAME_PLOT == 'directory':
            if RENAME_PLOT == 'chunklabel':
                chunk_label = os.path.splitext(os.path.basename(filename))[0]
                logger.debug('Chunk label: %s', chunk_label)
            elif RENAME_PLOT == 'directory':
                chunk_label = 'unnamed-chunk'
                PATH = self.settings.get(
                    'PATH', '%s/content' % settings.DEFAULT_CONFIG.get('PATH'))
                src_name = os.path.splitext(os.path.relpath(filename, PATH))[0]
                idx = KNITR.opts_chunk.names.index('set')
                knitroptschunk = {
                    'fig.path': '%s-' % os.path.join(FIG_PATH, src_name)
                }
                KNITR.opts_chunk[idx](
                    **{str(k): v
                       for k, v in knitroptschunk.items()})
                logger.debug('Figures path: %s, chunk label: %s',
                             knitroptschunk['fig.path'], chunk_label)
            R_OBJECTS.r('''
opts_knit$set(unnamed.chunk.label="{unnamed_chunk_label}")
render_markdown()
hook_plot <- knit_hooks$get('plot')
knit_hooks$set(plot=function(x, options) hook_plot(paste0("{SITEURL}/", x), options))
            '''.format(unnamed_chunk_label=chunk_label, SITEURL=site_url))
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            KNITR.knit(filename, md_filename, quiet=QUIET, encoding=ENCODING)
        # read md file - create a MarkdownReader
        # md_reader = readers.MarkdownReader(self.settings)
        md_reader = PandocReader(self.settings)
        content, metadata = md_reader.read(md_filename)
        # remove md file
        if CLEANUP:
            os.remove(md_filename)
        return content, metadata
    def test_pandoc_unsupported_minor_version(self):
        """Check if the installed pandoc has a supported minor version."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            PANDOC_EXECUTABLE_PATH="2.10/bin/pandoc",
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "empty.md")

        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Pandoc version must be 2.11 or higher.", message)
    def test_pandoc_availability_two(self):
        """Check if pandoc executable is available at the given path."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            PANDOC_EXECUTABLE_PATH="2.11/bin/pandoc",
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "empty.md")

        with self.assertRaises(Exception) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Could not find Pandoc. Please install.", message)
Beispiel #9
0
    def test_encoded_to_raw_conversion(self):
        """Check if raw paths are left untouched in output returned."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "valid_content_with_raw_paths.md")
        output, metadata = pandoc_reader.read(source_path)

        # Setting this so that assert is able to execute the difference
        self.maxDiff = None  # pylint: disable=invalid-name

        self.assertEqual(
            ("<p>This is some valid content that should pass."
             " If it does not pass we will know something is wrong.</p>\n"
             "<p>Our fictitious internal files are available"
             ' <a href="{filename}/path/to/file">at</a>:</p>\n'
             "<p>Our fictitious static files are available"
             ' <a href="{static}/path/to/file">at</a>:</p>\n'
             "<p>Our fictitious attachments are available"
             ' <a href="{attach}path/to/file">at</a>:</p>'),
            output,
        )

        self.assertEqual("Valid Content with Fictitious Raw Paths",
                         str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
    def test_mathjax_with_valid_defaults(self):
        """Check if mathematics is rendered correctly with defaults."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "valid_defaults.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)

        source_path = os.path.join(TEST_CONTENT_PATH, "mathjax_content.md")
        output, metadata = pandoc_reader.read(source_path)

        self.assertEqual(
            (
                '<p><span class="math display">\\[\n'
                "e^{i\\theta} = \\cos\\theta + i \\sin\\theta.\n"
                "\\]</span></p>"
            ),
            output,
        )

        self.assertEqual("MathJax Content", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
Beispiel #11
0
    def test_no_input_format(self):
        """Check if exception is raised if no input format is specified."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "no_input_format.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("No input format specified.", message)
Beispiel #12
0
    def test_invalid_self_contained(self):
        """Check if exception is raised if self-contained is true."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "selfcontained_true.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("The default self-contained should be set to false.",
                         message)
Beispiel #13
0
    def test_invalid_user_defined_wpm(self):
        """Check if exception is raised if words per minute is not a number."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            CALCULATE_READING_TIME=CALCULATE_READING_TIME,
            READING_SPEED="my words per minute",
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "reading_time_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("READING_SPEED setting must be a number.", message)
Beispiel #14
0
    def test_invalid_to_output_format(self):
        """Check if exception is raised if to output format is invalid."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH,
                         "invalid_to_output_format.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual("Output format type must be either html or html5.",
                         message)
    def test_pandoc_availability_one(self):
        """Check if Pandoc executable is available."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "empty.md")

        if not shutil.which("pandoc"):
            # Case where pandoc is not available
            with self.assertRaises(Exception) as context_manager:
                pandoc_reader.read(source_path)

            message = str(context_manager.exception)
            self.assertEqual("Could not find Pandoc. Please install.", message)
        else:
            self.assertTrue(True)
Beispiel #16
0
    def test_to_writer_both_given(self):
        """Check if exception is raised if to and writer are both given."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "to_writer_both_given.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")

        with self.assertRaises(ValueError) as context_manager:
            pandoc_reader.read(source_path)

        message = str(context_manager.exception)
        self.assertEqual(
            ("Specifying both to and writer is not supported."
             " Please specify just one."),
            message,
        )
Beispiel #17
0
    def test_default_wpm_reading_time(self):
        """Check if 200 words per minute give us reading time of 1 minute."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            CALCULATE_READING_TIME=CALCULATE_READING_TIME,
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "reading_time_content.md")
        _, metadata = pandoc_reader.read(source_path)

        self.assertEqual("1 minute", str(metadata["reading_time"]))
    def test_toc_with_valid_defaults(self):
        """Check if output and table of contents are valid with defaults."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "valid_defaults_with_toc.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)
        pandoc_reader = PandocReader(settings)

        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content_with_toc.md")
        output, metadata = pandoc_reader.read(source_path)
        self.maxDiff = None  # pylint: disable=invalid-name

        self.assertEqual(
            (
                "<p>This is some valid content that should pass."
                " If it does not pass we will know something is wrong.</p>\n"
                '<h2 id="first-heading">First Heading</h2>\n'
                "<p>This should be the first heading in my"
                " table of contents.</p>\n"
                '<h2 id="second-heading">Second Heading</h2>\n'
                "<p>This should be the second heading in my"
                " table of contents.</p>\n"
                '<h3 id="first-subheading">First Subheading</h3>\n'
                "<p>This is a subsection that should be shown as such"
                " in the table of contents.</p>\n"
                '<h3 id="second-subheading">Second Subheading</h3>\n'
                "<p>This is another subsection that should be shown as"
                " such in the table of contents.</p>"
            ),
            output,
        )

        self.assertEqual("Valid Content with Table of Contents", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
        self.assertEqual(
            '<nav class="toc" role="doc-toc">\n'
            "<ul>\n"
            '<li><a href="#first-heading">First Heading</a></li>\n'
            '<li><a href="#second-heading">Second Heading</a>\n'
            "<ul>\n"
            '<li><a href="#first-subheading">First Subheading</a></li>\n'
            '<li><a href="#second-subheading">Second Subheading</a></li>\n'
            "</ul></li>\n"
            "</ul>\n"
            "</nav>",
            str(metadata["toc"]),
        )
Beispiel #19
0
    def test_valid_content_with_toc_1(self):
        """Check if output returned is valid and table of contents is valid."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS + ["--toc"],
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "valid_content_with_toc.md")
        output, metadata = pandoc_reader.read(source_path)

        # Setting this so that assert is able to execute the difference
        self.maxDiff = None  # pylint: disable=invalid-name

        self.assertEqual(
            ("<p>This is some valid content that should pass."
             " If it does not pass we will know something is wrong.</p>\n"
             '<h2 id="first-heading">First Heading</h2>\n'
             "<p>This should be the first heading in my"
             " table of contents.</p>\n"
             '<h2 id="second-heading">Second Heading</h2>\n'
             "<p>This should be the second heading in my"
             " table of contents.</p>\n"
             '<h3 id="first-subheading">First Subheading</h3>\n'
             "<p>This is a subsection that should be shown as such"
             " in the table of contents.</p>\n"
             '<h3 id="second-subheading">Second Subheading</h3>\n'
             "<p>This is another subsection that should be shown as"
             " such in the table of contents.</p>"),
            output,
        )
        self.assertEqual("Valid Content with Table of Contents",
                         str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
        self.assertEqual(
            '<nav class="toc" role="doc-toc">\n'
            "<ul>\n"
            '<li><a href="#first-heading">First Heading</a></li>\n'
            '<li><a href="#second-heading">Second Heading</a>\n'
            "<ul>\n"
            '<li><a href="#first-subheading">First Subheading</a></li>\n'
            '<li><a href="#second-subheading">Second Subheading</a></li>\n'
            "</ul></li>\n"
            "</ul>\n"
            "</nav>",
            str(metadata["toc"]),
        )
Beispiel #20
0
    def test_user_defined_wpm_reading_time(self):
        """Check if 100 words per minute user defined gives us 2 minutes."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            CALCULATE_READING_TIME=CALCULATE_READING_TIME,
            READING_SPEED=100,
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "reading_time_content.md")
        _, metadata = pandoc_reader.read(source_path)

        self.assertEqual("2 minutes", str(metadata["reading_time"]))
Beispiel #21
0
    def test_valid_file(self):
        """Check if we get the appropriate output for valid input."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")
        output, metadata = pandoc_reader.read(source_path)

        self.assertEqual(
            ("<p>This is some valid content that should pass."
             " If it does not pass we"
             " will know something is wrong.</p>"),
            output,
        )

        self.assertEqual("Valid Content", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
Beispiel #22
0
    def test_mathjax_content(self):
        """Check if mathematics is rendered correctly."""
        settings = get_settings(PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
                                PANDOC_ARGS=PANDOC_ARGS)

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH, "mathjax_content.md")
        output, metadata = pandoc_reader.read(source_path)

        self.assertEqual(
            ('<p><span class="math display">\\[\n'
             "e^{i\\theta} = \\cos\\theta + i \\sin\\theta.\n"
             "\\]</span></p>"),
            output,
        )

        self.assertEqual("MathJax Content", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
Beispiel #23
0
    def test_summary(self):
        """Check if summary output is valid."""
        settings = get_settings(
            PANDOC_EXTENSIONS=PANDOC_EXTENSIONS,
            PANDOC_ARGS=PANDOC_ARGS,
            FORMATTED_FIELDS=FORMATTED_FIELDS,
        )

        pandoc_reader = PandocReader(settings)
        source_path = os.path.join(TEST_CONTENT_PATH,
                                   "valid_content_with_citation.md")
        _, metadata = pandoc_reader.read(source_path)

        self.assertEqual(
            ("But this foundational principle of science has now been"
             " called into question by"
             ' <a href="https://www.britannica.com/science/string-theory">'
             "String Theory</a>."),
            str(metadata["summary"]),
        )
    def test_valid_file_with_valid_defaults(self):
        """Check if we get the appropriate output specifying defaults."""
        pandoc_default_files = [
            os.path.join(TEST_DEFAULT_FILES_PATH, "valid_defaults.yaml")
        ]

        settings = get_settings(PANDOC_DEFAULT_FILES=pandoc_default_files)

        pandoc_reader = PandocReader(settings)

        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content.md")
        output, metadata = pandoc_reader.read(source_path)

        self.assertEqual(
            (
                "<p>This is some valid content that should pass."
                " If it does not pass we will know something is wrong.</p>"
            ),
            output,
        )

        self.assertEqual("Valid Content", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))
    def test_citations_and_with_citeproc_filter(self):
        """Check if output, citations are valid using citeproc filter."""
        pandoc_default_files = [
            os.path.join(
                TEST_DEFAULT_FILES_PATH,
                "valid_defaults_with_citeproc_filter.yaml",
            )
        ]

        settings = get_settings(
            PANDOC_DEFAULT_FILES=pandoc_default_files,
        )
        pandoc_reader = PandocReader(settings)

        source_path = os.path.join(TEST_CONTENT_PATH, "valid_content_with_citation.md")
        output, metadata = pandoc_reader.read(source_path)
        self.maxDiff = None  # pylint: disable=invalid-name

        self.assertEqual(
            (
                '<h2 id="string-theory">String Theory</h2>\n'
                "<p>But this foundational principle of science has"
                " now been called into question by"
                ' <a href="https://www.britannica.com/science/'
                'string-theory">String Theory</a>,'
                " which is a relative newcomer to theoretical physics, but one"
                " that has captured the common imagination, judging by"
                " the popular explanations that abound on the Web"
                ' <span class="citation" data-cites="mann2019 wood2019'
                ' jones2020">[1]–[3]</span>.'
                " And whether string theory is or is not science, Popper"
                " notwithstanding, is an issue that is still up for debate"
                " <span"
                ' class="citation" data-cites="siegel2015 castelvecchi2016'
                ' alves2017 francis2019">[4]–[7]</span>.</p>\n'
                '<h1 class="unnumbered" id="bibliography">References</h1>\n'
                '<div class="references csl-bib-body" id="refs"'
                ' role="doc-bibliography">\n'
                '<div class="csl-entry" id="ref-mann2019"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[1]'
                ' </div><div class="csl-right-inline">A. Mann,'
                " <span>“<span>What Is String Theory?</span>”</span>"
                " 20-Mar-2019. [Online]."
                ' Available: <a href="https://www.livescience.com/'
                '65033-what-is-string-theory.html">'
                "https://www.livescience.com/"
                "65033-what-is-string-theory.html</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-wood2019"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[2] </div>'
                '<div class="csl-right-inline">'
                "C. Wood, <span>“<span>What Is String Theory?</span>."
                " Reference article:"
                " A simplified explanation and brief history of string"
                " theory,”</span> 11-Jul-2019."
                ' [Online]. Available: <a href="https://www.space.com/'
                '17594-string-theory.html">'
                "https://www.space.com/17594-string-theory.html</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-jones2020"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[3]'
                ' </div><div class="csl-right-inline">'
                'A. Z. Jones, <span>“<span class="nocase">The Basics of String'
                " Theory</span>,”</span> 02-Mar-2019. [Online]. Available:"
                ' <a href="https://www.thoughtco.com/'
                'what-is-string-theory-2699363">'
                "https://www.thoughtco.com/what-is-string-theory-2699363</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-siegel2015"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[4]'
                ' </div><div class="csl-right-inline">'
                "E. Siegel, <span>“<span>Why String Theory Is Not A Scientific"
                " Theory</span>,”</span> 23-Dec-2015. [Online]. Available:"
                " <a"
                ' href="https://www.forbes.com/sites/'
                "startswithabang/2015/12/23/"
                'why-string-theory-is-not-science/">https://www.forbes.com/'
                "sites/startswithabang/2015/12/23/"
                "why-string-theory-is-not-science/</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-castelvecchi2016"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[5]'
                ' </div><div class="csl-right-inline">'
                'D. Castelvecchi, <span>“<span class="nocase">'
                "Feuding physicists turn"
                " to philosophy for help</span>. String theory is at the"
                " heart of a debate over the integrity of the scientific"
                " method itself,”</span> 05-Jan-2016. [Online]. Available:"
                ' <a href="https://www.nature.com/news/'
                'feuding-physicists-turn-to-philosophy-for-help-1.19076">'
                "https://www.nature.com/news/"
                "feuding-physicists-turn-to-philosophy-for-help-1.19076</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-alves2017"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[6] </div>'
                '<div class="csl-right-inline">'
                'R. A. Batista and J. Primack, <span>“<span class="nocase">'
                "Is String theory falsifiable?</span>. Can a theory that isn’t"
                " completely testable still be useful to physics?”</span>"
                " [Online]."
                ' Available: <a href="https://metafact.io/factchecks/'
                '30-is-string-theory-falsifiable">'
                "https://metafact.io/factchecks/"
                "30-is-string-theory-falsifiable</a>."
                " [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                '<div class="csl-entry" id="ref-francis2019"'
                ' role="doc-biblioentry">\n'
                '<div class="csl-left-margin">[7]'
                ' </div><div class="csl-right-inline">'
                'M. R. Francis, <span>“<span class="nocase">Falsifiability and'
                " physics</span>. Can a theory that isn’t completely testable"
                " still be useful to physics?”</span> 23-Apr-2019."
                " [Online]. Available:"
                ' <a href="https://www.scientificamerican.com/'
                'article/is-string-theory-science/">'
                "https://www.scientificamerican.com/article/is-"
                "string-theory-science/</a>. [Accessed: 12-Nov-2020]</div>\n"
                "</div>\n"
                "</div>"
            ),
            output,
        )

        self.assertEqual("Valid Content With Citation", str(metadata["title"]))
        self.assertEqual("My Author", str(metadata["author"]))
        self.assertEqual("2020-10-16 00:00:00", str(metadata["date"]))