Back to Repositories

Validating Document Class Core Functionality in DevDocs

This test suite validates core functionality of the Doc class in the DevDocs documentation system, focusing on document metadata handling, page building, and version management capabilities.

Test Coverage Overview

The test suite provides comprehensive coverage of the Doc class core functionality, including:

  • Document metadata management (name, slug, type, version)
  • Page building and storage operations
  • Version comparison and inheritance handling
  • JSON serialization and file storage mechanisms

Implementation Analysis

The testing approach utilizes RSpec/Minitest patterns with extensive use of stubs and mocks to isolate components. The suite employs behavior-driven development practices with descriptive contexts and nested describe blocks.

Key testing patterns include:
  • Shared context setup using let blocks
  • Mock object injection for storage operations
  • Isolated unit testing of version comparison logic

Technical Details

Testing tools and configuration:

  • Minitest as the testing framework
  • RSpec-style expectations syntax
  • Mock/stub utilities for isolation
  • JSON validation for serialization tests
  • File system abstractions for storage testing

Best Practices Demonstrated

The test suite exemplifies several testing best practices including proper isolation of dependencies, comprehensive edge case coverage, and clear test organization.

  • Thorough setup and teardown management
  • Consistent naming conventions
  • Comprehensive assertion coverage
  • Clear test case organization

freecodecamp/devdocs

test/lib/docs/core/doc_test.rb

            
require_relative '../../../test_helper'
require_relative '../../../../lib/docs'

class DocsDocTest < Minitest::Spec
  let :doc do
    Class.new Docs::Doc do
      self.name = 'name'
      self.type = 'type'
    end
  end

  let :page do
    { path: 'path', store_path: 'store_path', output: 'output', entries: [entry] }
  end

  let :entry do
    Docs::Entry.new 'name', 'path', 'type'
  end

  let :store do
    Docs::NullStore.new
  end

  describe ".inherited" do
    it "sets .type" do
      assert_equal doc.type, Class.new(doc).type
    end
  end

  describe ".name" do
    it "returns 'Doc' when the class is Docs::Doc" do
      assert_equal 'Doc', Docs::Doc.name
    end
  end

  describe ".name=" do
    it "stores .name" do
      doc.name = 'test'
      assert_equal 'test', doc.name
    end
  end

  describe ".slug" do
    it "returns 'doc' when the class is Docs::Doc" do
      assert_equal 'doc', Docs::Doc.slug
    end

    it "returns 'doc~4.2_lts' when the class is Docs::Doc and its #version is '42 LTS'" do
      stub(Docs::Doc).version { '4.2 LTS' }
      assert_equal 'doc~4.2_lts', Docs::Doc.slug
    end

    it "returns 'foo~42' when #slug has been set to 'foo' and #version to '42'" do
      doc.slug = 'foo'
      doc.version = '42'
      assert_equal 'foo~42', doc.slug
    end

    it "returns 'foobar' when #name has been set to 'FooBar'" do
      doc.name = 'FooBar'
      assert_equal 'foobar', doc.slug
    end

    it "raises error when #name has unsluggable characters" do
      assert_raises do
        doc.name = 'Foo-Bar'
        doc.slug
      end
    end
  end

  describe ".slug=" do
    it "stores .slug" do
      doc.slug = 'test'
      assert_equal 'test', doc.slug
    end
  end

  describe ".version=" do
    it "stores .version as a string" do
      doc.version = 4815162342
      assert_equal '4815162342', doc.version
    end
  end

  describe ".release=" do
    it "stores .release" do
      doc.release = '1'
      assert_equal '1', doc.release
    end
  end

  describe ".links=" do
    it "stores .links" do
      doc.links = { test: true }
      assert_equal({ test: true }, doc.links)
    end
  end

  describe ".abstract" do
    it "returns nil" do
      assert_nil doc.abstract
    end
  end

  describe ".abstract=" do
    it "stores .abstract" do
      doc.abstract = true
      assert doc.abstract
    end
  end

  describe ".path" do
    it "returns .slug" do
      doc.slug = 'slug'
      assert_equal 'slug', doc.path
    end
  end

  describe ".index_path" do
    it "returns .path + ::INDEX_FILENAME" do
      stub(doc).path { 'path' }
      assert_equal File.join('path', Docs::Doc::INDEX_FILENAME), doc.index_path
    end
  end

  describe ".db_path" do
    it "returns .path + ::DB_FILENAME" do
      stub(doc).path { 'path' }
      assert_equal File.join('path', Docs::Doc::DB_FILENAME), doc.db_path
    end
  end

  describe ".meta_path" do
    it "returns .path + ::META_FILENAME" do
      stub(doc).path { 'path' }
      assert_equal File.join('path', Docs::Doc::META_FILENAME), doc.meta_path
    end
  end

  describe ".new" do
    it "raises an error when .abstract is true" do
      doc.abstract = true
      assert_raises NotImplementedError do
        doc.new
      end
    end
  end

  describe ".as_json" do
    it "returns a hash" do
      assert_instance_of Hash, doc.as_json
    end

    it "includes the doc's name, slug, type, version, and release" do
      assert_equal %i(name slug type), doc.as_json.keys

      %w(name slug type version release links).each do |attribute|
        eval "stub(doc).#{attribute} { attribute }"
        assert_equal attribute, doc.as_json[attribute.to_sym]
      end
    end

    it "includes the doc's version when it's defined and nil" do
      refute doc.as_json.key?(:version)
      doc.version = nil
      assert doc.as_json.key?(:version)
    end
  end

  describe ".store_page" do
    it "builds a page" do
      any_instance_of(doc) do |instance|
        stub(instance).build_page('id') { @called = true; nil }
      end
      doc.store_page(store, 'id') {}
      assert @called
    end

    context "when the page builds successfully" do
      before do
        any_instance_of(doc) do |instance|
          stub(instance).build_page { page }
        end
      end

      context "and it has :entries" do
        it "returns true" do
          assert doc.store_page(store, 'id')
        end

        it "stores a file" do
          mock(store).write(page[:store_path], page[:output])
          doc.store_page(store, 'id')
        end

        it "opens the .path directory before storing the file" do
          stub(doc).path { 'path' }
          stub(store).write { assert false }
          mock(store).open('path') do |_, &block|
            stub(store).write
            block.call
          end
          doc.store_page(store, 'id')
        end
      end

      context "and it doesn't have :entries" do
        before do
          page[:entries] = []
        end

        it "returns false" do
          refute doc.store_page(store, 'id')
        end

        it "doesn't store a file" do
          dont_allow(store).write
          doc.store_page(store, 'id')
        end
      end
    end

    context "when the page doesn't build successfully" do
      before do
        any_instance_of(doc) do |instance|
          stub(instance).build_page { nil }
        end
      end

      it "returns false" do
        refute doc.store_page(store, 'id')
      end

      it "doesn't store a file" do
        dont_allow(store).write
        doc.store_page(store, 'id')
      end
    end
  end

  describe ".store_pages" do
    it "build the pages" do
      any_instance_of(doc) do |instance|
        stub(instance).build_pages { @called = true }
      end
      doc.store_pages(store) {}
      assert @called
    end

    context "when pages are built successfully" do
      let :pages do
        [
          page.deep_dup.tap { |p| page[:entries].first.tap { |e| e.name = 'one' } },
          page.deep_dup.tap { |p| page[:entries].first.tap { |e| e.name = 'two' } }
        ]
      end

      before do
        any_instance_of(doc) do |instance|
          stub(instance).build_pages { |&block| pages.each(&block) }
        end
      end

      context "and at least one page has :entries" do
        it "returns true" do
          assert doc.store_pages(store)
        end

        it "stores a file for each page that has :entries" do
          pages.first.merge!(entries: [], output: '')
          mock(store).write(page[:store_path], page[:output])
          mock(store).write('index.json', anything)
          mock(store).write('db.json', anything)
          mock(store).write('meta.json', anything)
          doc.store_pages(store)
        end

        it "stores an index that contains all the pages' entries" do
          stub(store).write(page[:store_path], page[:output])
          stub(store).write('db.json', anything)
          stub(store).write('meta.json', anything)
          mock(store).write('index.json', anything) do |path, json|
            json = JSON.parse(json)
            assert_equal pages.length, json['entries'].length
            assert_includes json['entries'], Docs::Entry.new('one', 'path', 'type').as_json.stringify_keys
          end
          doc.store_pages(store)
        end

        it "stores a db that contains all the pages, indexed by path" do
          stub(store).write(page[:store_path], page[:output])
          stub(store).write('index.json', anything)
          stub(store).write('meta.json', anything)
          mock(store).write('db.json', anything) do |path, json|
            json = JSON.parse(json)
            assert_equal page[:output], json[page[:path]]
          end
          doc.store_pages(store)
        end

        it "stores a meta file that contains the doc's metadata" do
          stub(store).write(page[:store_path], page[:output])
          stub(store).write('index.json', anything)
          stub(store).write('db.json', anything)
          mock(store).write('meta.json', anything) do |path, json|
            json = JSON.parse(json)
            assert_equal %w(name slug type mtime db_size).sort, json.keys.sort
          end
          doc.store_pages(store)
        end

        it "replaces the .path directory before storing the files" do
          stub(doc).path { 'path' }
          stub(store).write { assert false }
          mock(store).replace('path') do |_, &block|
            stub(store).write
            block.call
          end
          doc.store_pages(store)
        end
      end

      context "and no pages have :entries" do
        before do
          pages.each { |page| page[:entries] = [] }
        end

        it "returns false" do
          refute doc.store_pages(store)
        end

        it "doesn't store files" do
          dont_allow(store).write
          doc.store_pages(store)
        end
      end
    end

    context "when no pages are built successfully" do
      before do
        any_instance_of(doc) do |instance|
          stub(instance).build_pages
        end
      end

      it "returns false" do
        refute doc.store_pages(store)
      end

      it "doesn't store files" do
        dont_allow(store).write
        doc.store_pages(store)
      end
    end
  end

  describe ".versions" do
    it "returns [self] if no versions have been created" do
      assert_equal [doc], doc.versions
    end
  end

  describe ".version" do
    context "with no args" do
      it "returns @version by default" do
        doc.version = 'v'
        assert_equal 'v', doc.version
      end
    end

    context "with args" do
      it "creates a version subclass" do
        version = doc.version('4') { self.release = '8'; self.links = ["https://#{self.version}"] }

        assert_equal [version], doc.versions

        assert_nil doc.version
        assert_nil doc.release
        refute doc.version?

        assert version.version?
        assert_equal '4', version.version
        assert_equal '8', version.release
        assert_equal 'name', version.name
        assert_equal 'type', version.type
        assert_equal ['https://4'], version.links
      end
    end

    it "compares versions" do
      instance = doc.versions.first.new
      assert_equal "Up-to-date", instance.outdated_state('0.0.2', '0.0.3')
      assert_equal "Outdated major version", instance.outdated_state('0.2', '0.3')
      assert_equal 'Up-to-date', instance.outdated_state('1', '1')
      assert_equal 'Up-to-date', instance.outdated_state('1.2', '1.2')
      assert_equal 'Up-to-date', instance.outdated_state('1.2.2', '1.2.2')
      assert_equal 'Up-to-date', instance.outdated_state('1.2.2', '1.2.3')
      assert_equal "Outdated major version", instance.outdated_state('1', '2')
      assert_equal "Up-to-date", instance.outdated_state('1.0.2', '1.0.3')
      assert_equal "Outdated major version", instance.outdated_state('1.2', '1.3')
      assert_equal "Outdated minor version", instance.outdated_state('2.2', '2.3')
      assert_equal "Outdated major version", instance.outdated_state('9', '10')
      assert_equal "Outdated major version", instance.outdated_state('99', '101')
      assert_equal 'Up-to-date', instance.outdated_state('2006-01-02', '2006-01-03')
      assert_equal "Outdated minor version", instance.outdated_state('2006-01-02', '2006-02-03')
    end
  end
end