Skip to content

Add comprehensive unit tests for uncovered areas#6

Merged
Pentusha merged 11 commits into
mainfrom
copilot/analyze-test-coverage
May 4, 2026
Merged

Add comprehensive unit tests for uncovered areas#6
Pentusha merged 11 commits into
mainfrom
copilot/analyze-test-coverage

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 4, 2026

Summary

Adds 10 new unit-test files (1,216 lines) covering previously uncovered areas in both v1 and v2 APIs. All tests are pure unit tests — no database required — and focus on edge cases, error paths, and fallback behaviour.

What’s new

File Scope Key coverage
tests/v1/test_unit/test_enums_and_exceptions.py v1 enums & exceptions OrderByDirections, FKNotFoundError, AlreadyExistsError, NotFoundError
tests/v1/test_unit/test_schemas_base.py v1 schemas normalize_datetime_to_utc, utc_datetime_encoder, datetime_encoder, PaginationMetaSchema, AdminMeta, ClientMeta, Filter, OrderBy, OrFilterGroup
tests/v1/test_unit/test_utils.py utilities now_without_tz, validate_exclusive_presence (including falsy-but-not-None edge cases)
tests/v2/test_unit/test_exceptions.py v2 exceptions FKNotFoundError, AlreadyExistsError, NotFoundError
tests/v2/test_unit/test_factory.py factories build_repository, build_service, build_service_for_repo — standard & soft-delete variants, custom classes, config propagation, error paths
tests/v2/test_unit/test_payload_mixin.py payload mixin _dump_payload with dict and Pydantic-model inputs, exclude_unset behaviour
tests/v2/test_unit/test_query_dsl_tokens.py query DSL parse_filter_token, parse_sort_token, apply_filter_operator, resolve_to_column, build_filter_clauses, build_sort_clauses, build_query_params — all operators, error paths, predicate fields, empty-token handling
tests/v2/test_unit/test_schemas_base.py v2 schemas ClientMeta, PaginationMetaSchema.calculate (negative-total clamping)
tests/v2/test_unit/test_serializer_mixin.py serializer mixin serialize_one, serialize_many — explicit schema arg, fallback to detail_schema / list_schema, empty-list handling, prefer_list_schema flag
tests/v2/test_unit/test_updated_by_mixin.py updated-by mixin _apply_updated_byactor_id injection, preservation of existing value, missing-attribute error, custom attribute name

Fixes applied

  1. Soft-delete factory tests — added _SoftWidget(SoftDeletableModel) so SoftDeleteRepository.__init__ succeeds (models must expose deleted_at).
  2. Query-DSL rendering — replaced str(col) with _render(col) (PostgreSQL dialect + literal binds) for deterministic assertions.
  3. Mypy strict-mode compliance — cast resolve_to_column results to ColumnElement[Any] before passing to _render.
  4. Additional fix — added missing Any type parameter to ColumnElement casts in test_query_dsl_tokens.py to satisfy mypy strict = true.

Coverage impact

Metric Before After
Total ~84 % 90 %
src/notora/utils/validation.py partial 100 %
src/notora/v1/exceptions/common.py partial 100 %
src/notora/v1/schemas/base.py partial 99 %
src/notora/v2/exceptions/common.py partial 100 %
src/notora/v2/repositories/query_dsl.py partial 95 %
src/notora/v2/services/mixins/updated_by.py partial 100 %
src/notora/v2/services/mixins/payload.py partial 100 %
src/notora/v2/services/mixins/serializer.py partial 100 %

Verification

  • make lint passes (ruff, mypy, pyright, stubtest)
  • make test passes (345 tests)
  • No breaking changes to public API

Follow-up ideas (out of scope)

  • v2/enums/* is still at 0 % direct coverage — tiny import-level tests could be added.
  • v2/services/mixins/m2m.py has several uncovered branches (bulk-attach edge cases, rollback paths).
  • v1/persistence/repos/base.py and v1/services/base.py remain at ~70 %; full coverage would require heavy mocking of SQLAlchemy sessions.

Copilot AI and others added 2 commits May 4, 2026 11:35
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/a8913a70-7492-4b98-b1f5-dbd935cdb637

Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/a8913a70-7492-4b98-b1f5-dbd935cdb637

Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/0c9226ce-dcec-448f-9dec-dd4ef561c525

Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
…ve_to_column assertions

Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/92bb63bf-07cf-4012-bba6-1fb6dda66289

Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
…e passing to _render

Agent-Logs-Url: https://github.com/AldanDev/Notora/sessions/8d88a3ea-029a-49eb-9e7a-7eb4399e3242

Co-authored-by: Pentusha <1904496+Pentusha@users.noreply.github.com>
Copy link
Copy Markdown
Member

@Pentusha Pentusha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall Assessment

Approve with minor nits. This is a solid, well-structured test PR that meaningfully increases coverage (+6 pp) without touching production code. The tests are focused, fast, and exercise edge cases effectively.


Highlights

  • Good separation of concerns. Each test file maps cleanly to a single module or mixin.
  • Edge-case coverage. test_utils.py correctly tests falsy-but-not-None values (0, "", []). test_serializer_mixin.py covers empty lists, schema overrides, and fallback chains.
  • Factory tests are thorough. test_factory.py validates not just happy paths but also the TypeError raised when a soft-delete service class is paired with a non-soft-delete repo.
  • Query-DSL tests are comprehensive. All nine filter operators, sort directions, predicate fields, and error paths are covered. Using PostgreSQL dialect compilation with literal binds makes assertions deterministic.
  • No database required. All new tests are pure unit tests, keeping the feedback loop fast.

Minor Issues / Nits

1. ColumnElement type-arg consistency

test_query_dsl_tokens.py already casts to ColumnElement[Any] in two places (fixed in this PR), but the _render helper itself is typed as ColumnElement without a parameter:

def _render(clause: ColumnElement) -> str:  # type: ignore[type-arg]

Consider aligning it with ColumnElement[Any] and removing the # type: ignore[type-arg] for consistency.

2. v2/enums still uncovered

src/notora/v2/enums/__init__.py and src/notora/v2/enums/base.py remain at 0 % coverage. They are tiny (6 lines total), so a single test file importing and asserting OrderByDirections.ASC.value == "asc" would bring them to 100 % with minimal effort.

3. _make_obj helper in test_serializer_mixin.py

Using types.SimpleNamespace() is clever for from_attributes=True schemas, but it’s worth adding a short comment explaining why it works (no required SQLAlchemy-mapped fields), so future readers don’t assume it’s a general-purpose model mock.

4. Exception test duplication

tests/v1/test_unit/test_enums_and_exceptions.py and tests/v2/test_unit/test_exceptions.py share nearly identical assertions for FKNotFoundError, AlreadyExistsError, and NotFoundError. This is expected because the classes are duplicated across versions, but if the project ever deduplicates them, both files will need updating.


Suggestions for Follow-up PRs

  1. Cover m2m mixin branchessrc/notora/v2/services/mixins/m2m.py has several uncovered rollback / bulk-attach paths.
  2. Cover v2/enums — trivial 6-line win.
  3. Property-based testshypothesis is already in the lockfile (via README.md reference). A few property-based tests for PaginationMetaSchema.calculate or validate_exclusive_presence could catch boundary bugs automatically.

Checklist Verification

Check Status
Lint (ruff, mypy, pyright, stubtest) ✅ Pass
Tests (345/345) ✅ Pass
No production-code changes ✅ Confirmed
Coverage increase ✅ 84 % → 90 %

@Pentusha Pentusha requested a review from Copilot May 4, 2026 12:41
@Pentusha Pentusha marked this pull request as ready for review May 4, 2026 12:42
@Pentusha Pentusha closed this May 4, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds broad unit-test coverage for previously under-tested v1/v2 helpers, schemas, exceptions, factories, and service mixins, plus a small typing cleanup in pytest fixtures. This strengthens confidence in core library behavior without changing production APIs.

Changes:

  • Adds new v1 unit tests for enums, exceptions, schema helpers, pagination metadata, and validation/time utilities.
  • Adds new v2 unit tests for exceptions, factories, query DSL token parsing/building, payload/serializer/updated-by mixins, and base schemas.
  • Cleans up pytest fixture typing and updates an existing query-schema test helper for deterministic SQL rendering.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/v2/test_unit/test_updated_by_mixin.py Adds unit coverage for UpdatedByServiceMixin payload injection and error paths.
tests/v2/test_unit/test_serializer_mixin.py Adds serializer mixin tests for schema fallback and error behavior.
tests/v2/test_unit/test_schemas_base.py Adds v2 schema tests for ClientMeta and pagination total clamping.
tests/v2/test_unit/test_query_dsl_tokens.py Adds broad query DSL parser/clause-builder coverage.
tests/v2/test_unit/test_pydantic_query_schemas.py Refactors SQL rendering helper to use a PostgreSQL dialect instance.
tests/v2/test_unit/test_payload_mixin.py Adds _dump_payload unit tests for dict and Pydantic inputs.
tests/v2/test_unit/test_factory.py Adds coverage for repository/service factory helpers and soft-delete variants.
tests/v2/test_unit/test_exceptions.py Adds v2 exception behavior tests.
tests/v2/conftest.py Adds a concrete type annotation for the fixture request object.
tests/v1/test_unit/test_utils.py Adds coverage for time and exclusive-presence validation utilities.
tests/v1/test_unit/test_schemas_base.py Adds v1 schema/helper tests for datetime handling, pagination, filters, and ordering.
tests/v1/test_unit/test_enums_and_exceptions.py Adds v1 enum and exception tests.
tests/conftest.py Adds typing to the custom pytest option hook.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/conftest.py Outdated
Comment thread tests/v2/test_unit/test_factory.py Outdated
Comment thread tests/v1/test_unit/test_schemas_base.py Outdated
Comment thread tests/v2/test_unit/test_updated_by_mixin.py Outdated
Comment thread tests/v2/test_unit/test_updated_by_mixin.py Outdated
@Pentusha Pentusha reopened this May 4, 2026
Pentusha added 2 commits May 4, 2026 15:49
- Use pytest.Parser instead of _pytest private import
- Rename test to match actual behavior (soft-delete flag + explicit service class)
- Rename filter default op test to reflect '=' not 'eq'
- Use Mapped[UUID | None] instead of Mapped[object] in updated_by test doubles
@Pentusha Pentusha merged commit 78b2a62 into main May 4, 2026
11 checks passed
@Pentusha Pentusha deleted the copilot/analyze-test-coverage branch May 4, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants