diff --git a/.editorconfig b/.editorconfig index ebe7f86..dce09d2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,224 +1,127 @@ -# Remove the line below if you want to inherit .editorconfig settings from higher directories +# Remove the line below if you want to inherit .editorconfig settings from higher directories. root = true -# C# files +[*] +end_of_line = lf +insert_final_newline = true + +[*.{cmd,ps1}] +end_of_line = crlf + [*.cs] -guidelines = 120, 140 +guidelines = 120 +max_line_length = 100 -#### Core EditorConfig Options #### +csharp_style_namespace_declarations = file_scoped +dotnet_code_quality.CA1062.null_check_validation_methods = CreateAndFake.Design.ArgumentGuard.ThrowIfNull -# Indentation and spacing -indent_size = 4 -indent_style = space -tab_width = 4 +#### Naming styles: #### -# New line preferences -end_of_line = crlf -insert_final_newline = false - -#### .NET Coding Conventions #### - -# Organize usings -dotnet_separate_import_directive_groups = false -dotnet_sort_system_directives_first = true - -# this. and Me. preferences -dotnet_style_qualification_for_event = false:silent -dotnet_style_qualification_for_field = false:silent -dotnet_style_qualification_for_method = false:silent -dotnet_style_qualification_for_property = false:silent - -# Language keywords vs BCL types preferences -dotnet_style_predefined_type_for_locals_parameters_members = true:silent -dotnet_style_predefined_type_for_member_access = true:silent - -# Parentheses preferences -dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent -dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent -dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent - -# Modifier preferences -dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent - -# Expression-level preferences -csharp_style_deconstructed_variable_declaration = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_throw_expression = true:suggestion -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_object_initializer = true:suggestion -dotnet_style_prefer_auto_properties = true:silent -dotnet_style_prefer_compound_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:silent -dotnet_style_prefer_conditional_expression_over_return = true:silent -dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_inferred_tuple_names = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion - -# Field preferences -dotnet_style_readonly_field = true:suggestion - -# Parameter preferences -dotnet_code_quality_unused_parameters = all:suggestion - -#### C# Coding Conventions #### - -# var preferences -csharp_style_var_elsewhere = false:silent -csharp_style_var_for_built_in_types = false:silent -csharp_style_var_when_type_is_apparent = false:silent - -# Expression-bodied members -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent - -# Pattern matching preferences -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_prefer_switch_expression = true:suggestion - -# Null-checking preferences -csharp_style_conditional_delegate_call = true:suggestion - -# Modifier preferences -csharp_prefer_static_local_function = true:suggestion -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async - -# Code-block preferences -csharp_prefer_braces = true:silent -csharp_prefer_simple_using_statement = true:suggestion - -# Expression-level preferences -csharp_prefer_simple_default_expression = true:suggestion -csharp_style_pattern_local_over_anonymous_function = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_range_operator = true:suggestion -csharp_style_unused_value_assignment_preference = discard_variable:suggestion -csharp_style_unused_value_expression_statement_preference = discard_variable:silent - -# 'using' directive preferences -csharp_using_directive_placement = outside_namespace:silent - -#### C# Formatting Rules #### - -# New line preferences -csharp_new_line_before_catch = true -csharp_new_line_before_else = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_anonymous_types = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_open_brace = all -csharp_new_line_between_query_expression_clauses = true - -# Indentation preferences -csharp_indent_block_contents = true -csharp_indent_braces = false -csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = true -csharp_indent_labels = one_less_than_current -csharp_indent_switch_labels = true - -# Space preferences -csharp_space_after_cast = false -csharp_space_after_colon_in_inheritance_clause = true -csharp_space_after_comma = true -csharp_space_after_dot = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = before_and_after -csharp_space_around_declaration_statements = false -csharp_space_before_colon_in_inheritance_clause = true -csharp_space_before_comma = false -csharp_space_before_dot = false -csharp_space_before_open_square_brackets = false -csharp_space_before_semicolon_in_for_statement = false -csharp_space_between_empty_square_brackets = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_parameter_list_parentheses = false -csharp_space_between_method_declaration_empty_parameter_list_parentheses = false -csharp_space_between_method_declaration_name_and_open_parenthesis = false -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_parentheses = false -csharp_space_between_square_brackets = false - -# Wrapping preferences -csharp_preserve_single_line_blocks = true -csharp_preserve_single_line_statements = true - -#### Naming styles #### - -# Naming rules - -dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion -dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface -dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i - -dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.types_should_be_pascal_case.symbols = types -dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case - -dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion -dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members -dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case - -dotnet_naming_rule.private_or_internal_static_field_should_be_begins_with__pascal.severity = warning -dotnet_naming_rule.private_or_internal_static_field_should_be_begins_with__pascal.symbols = private_or_internal_static_field -dotnet_naming_rule.private_or_internal_static_field_should_be_begins_with__pascal.style = begins_with__pascal - -dotnet_naming_rule.private_or_internal_field_should_be_begins_with__camel.severity = warning -dotnet_naming_rule.private_or_internal_field_should_be_begins_with__camel.symbols = private_or_internal_field -dotnet_naming_rule.private_or_internal_field_should_be_begins_with__camel.style = begins_with__camel - -# Symbol specifications - -dotnet_naming_symbols.interface.applicable_kinds = interface -dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal -dotnet_naming_symbols.interface.required_modifiers = - -dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field -dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private -dotnet_naming_symbols.private_or_internal_field.required_modifiers = - -dotnet_naming_symbols.private_or_internal_static_field.applicable_kinds = field -dotnet_naming_symbols.private_or_internal_static_field.applicable_accessibilities = internal, private -dotnet_naming_symbols.private_or_internal_static_field.required_modifiers = static - -dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum -dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal -dotnet_naming_symbols.types.required_modifiers = - -dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method -dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal -dotnet_naming_symbols.non_field_members.required_modifiers = - -# Naming styles - -dotnet_naming_style.pascal_case.required_prefix = -dotnet_naming_style.pascal_case.required_suffix = -dotnet_naming_style.pascal_case.word_separator = -dotnet_naming_style.pascal_case.capitalization = pascal_case +# Define naming styles: +dotnet_naming_style.underscored_camel.required_prefix = _ +dotnet_naming_style.underscored_camel.capitalization = camel_case + +dotnet_naming_style.underscored_pascal.required_prefix = _ +dotnet_naming_style.underscored_pascal.capitalization = pascal_case -dotnet_naming_style.begins_with_i.required_prefix = I -dotnet_naming_style.begins_with_i.required_suffix = -dotnet_naming_style.begins_with_i.word_separator = -dotnet_naming_style.begins_with_i.capitalization = pascal_case +dotnet_naming_style.underscored_i.required_prefix = I +dotnet_naming_style.underscored_i.capitalization = pascal_case -dotnet_naming_style.begins_with__camel.required_prefix = _ -dotnet_naming_style.begins_with__camel.required_suffix = -dotnet_naming_style.begins_with__camel.word_separator = -dotnet_naming_style.begins_with__camel.capitalization = camel_case +dotnet_naming_style.pascal_case.capitalization = pascal_case -dotnet_naming_style.begins_with__pascal.required_prefix = _ -dotnet_naming_style.begins_with__pascal.required_suffix = -dotnet_naming_style.begins_with__pascal.word_separator = -dotnet_naming_style.begins_with__pascal.capitalization = pascal_case +dotnet_naming_style.camel_case.capitalization = camel_case + +# Define symbol groups: +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.interfaces.applicable_kinds = interface + +dotnet_naming_symbols.structures.applicable_kinds = class, struct, interface, enum, property, event, method, type_parameter + +dotnet_naming_symbols.locals.applicable_kinds = parameters, local, local_function + +# Define naming rules: +dotnet_naming_rule.private_fields_prefix.symbols = private_fields +dotnet_naming_rule.private_fields_prefix.style = underscored_camel +dotnet_naming_rule.private_fields_prefix.severity = warning + +dotnet_naming_rule.private_static_fields_prefix.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_prefix.style = underscored_pascal +dotnet_naming_rule.private_static_fields_prefix.severity = warning + +dotnet_naming_rule.interfaces_prefix.symbols = interfaces +dotnet_naming_rule.interfaces_prefix.style = begins_with_i +dotnet_naming_rule.interfaces_prefix.severity = warning + +dotnet_naming_rule.structures_casing.symbols = structures +dotnet_naming_rule.structures_casing.style = pascal_case +dotnet_naming_rule.structures_casing.severity = warning + +dotnet_naming_rule.locals_casing.symbols = locals +dotnet_naming_rule.locals_casing.style = camel_case +dotnet_naming_rule.locals_casing.severity = warning + +#### Analyzer Overrides #### + +dotnet_analyzer_diagnostic.severity = warning + +# Controlled by CSharpier. +dotnet_diagnostic.IDE0055.severity = None +dotnet_diagnostic.MA0051.severity = None + +# Bad warnings that can create bugs or are clearly intended behavior. +dotnet_diagnostic.CA1000.severity = None +dotnet_diagnostic.CA1040.severity = None +dotnet_diagnostic.MA0018.severity = None +dotnet_diagnostic.MA0165.severity = None +dotnet_diagnostic.RCS1241.severity = None +dotnet_diagnostic.S1133.severity = None +dotnet_diagnostic.S1694.severity = None +dotnet_diagnostic.S1994.severity = None +dotnet_diagnostic.S3011.severity = None +dotnet_diagnostic.S3220.severity = None +dotnet_diagnostic.S3453.severity = None +dotnet_diagnostic.S3878.severity = None + +# Redundancy that's good for clarity. +dotnet_diagnostic.CA1805.severity = None +dotnet_diagnostic.RCS1033.severity = None +dotnet_diagnostic.RCS1034.severity = None +dotnet_diagnostic.RCS1071.severity = None +dotnet_diagnostic.RCS1129.severity = None +dotnet_diagnostic.RCS1188.severity = None +dotnet_diagnostic.S108.severity = None +dotnet_diagnostic.S1125.severity = None +dotnet_diagnostic.S1199.severity = None +dotnet_diagnostic.S3626.severity = None + +# Unnecessary overcaution against default behavior that hurts readability. +dotnet_diagnostic.IDE0045.severity = None +dotnet_diagnostic.IDE0046.severity = None +dotnet_diagnostic.IDE0048.severity = None +dotnet_diagnostic.MA0002.severity = None +dotnet_diagnostic.MA0003.severity = None +dotnet_diagnostic.MA0006.severity = None +dotnet_diagnostic.MA0076.severity = None +dotnet_diagnostic.MA0169.severity = None +dotnet_diagnostic.RCS1089.severity = None +dotnet_diagnostic.RCS1123.severity = None +dotnet_diagnostic.S1751.severity = None +dotnet_diagnostic.S2743.severity = None +dotnet_diagnostic.S3993.severity = None + +# Design choice. +dotnet_diagnostic.MA0029.severity = None +dotnet_diagnostic.MA0071.severity = None +dotnet_diagnostic.RCS1112.severity = None +dotnet_diagnostic.RCS1211.severity = None +dotnet_diagnostic.S3267.severity = None + +# Deprecated. +dotnet_diagnostic.MA0038.severity = None +dotnet_diagnostic.MA0041.severity = None diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1f43934 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +* text=auto eol=lf +*.cmd text eol=crlf +*.ps1 text eol=crlf diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 7e77a3a..ea57a59 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -1,46 +1,91 @@ -# Contributor Covenant Code of Conduct +# Contributor Covenant 3.0 Code of Conduct ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +We pledge to make our community welcoming, safe, and equitable for all. -## Our Standards +We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant. -Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +## Encouraged Behaviors -Examples of unacceptable behavior by participants include: +While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language. -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including: -## Our Responsibilities +1. Respecting the **purpose of our community**, our activities, and our ways of gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our community**. -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +## Restricted Behaviors -## Scope +We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct. + +1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. + +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content you contribute. +3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors. + + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a possible violation, **email [support@werecodent.com](mailto:support@werecodent.com)**. + +Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. -## Enforcement +## Addressing and Repairing Harm -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +**** + +If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped. + +1) Warning + 1) Event: A violation involving a single incident or series of incidents. + 2) Consequence: A private, written warning from the Community Moderators. + 3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations. +2) Temporarily Limited Activities + 1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation. + 2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members. + 3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over. +3) Temporary Suspension + 1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation. + 2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. + 3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted. +4) Permanent Ban + 1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member. + 2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior. + 3) Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community. + + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). + +Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion). diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7fd5cf3..d1fe17b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,11 +4,12 @@ Thank you for your interest in contributing. Please first discuss the change you wish to make via issue/request, email, or any other method with the owners of this repository before making changes. Failure to do so will likely lead to a declined pull request regardless of quality. -Make sure to refer to and follow the [code of conduct](CODE_OF_CONDUCT.md). +Make sure to refer to and follow the [code of conduct](CODE_OF_CONDUCT.md). For environment setup, refer to the [support](SUPPORT.md) page. ## Quality Requirements -* Minimal external dependencies. +* No AI-generated LLM code contributions. +* Digitally signed (see DCO below). * 100% test coverage. * Proper comments. * Updated documentation. @@ -17,28 +18,7 @@ Make sure to refer to and follow the [code of conduct](CODE_OF_CONDUCT.md). Pull requests will be reviewed thoroughly to maintain project quality. -## Windows Environment Recommended Setup - -1) Install [VS Community](https://visualstudio.microsoft.com/vs/community/). -2) Clone the repository locally. -3) To see build options, run from cmd prompt: "./build/run.cmd --help" -4) Verify project state by running from cmd prompt: "./build/run.cmd test" - -## Linux Environment Recommended Setup - -1) Install packages for: - A) [.NET frameworks](https://dotnet.microsoft.com/download/) - B) [Mono](https://www.mono-project.com/download/stable/#download-lin/) - C) [VS Code](https://code.visualstudio.com/download/) -2) Install VS Code extensions: - A) C# - B) EditorConfig for VS Code - C) Powershell - D) Code Spell Checker -3) Clone the repository locally. -4) Run from terminal: "chmod +x ./build/run.sh" -5) To see build options, run from terminal: "./build/run.sh --help" -6) Verify project state by running from terminal: "./build/run.sh test" +Note the ban on LLM-generated code. Developers do not have the right to submit LLM-generated code because that code can be incompatibly copyrighted or licensed elsewhere. Review the Developer Certificate of Origin adherence requirements below. ## Developer Certificate of Origin (DCO) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/1-feature_request.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to .github/ISSUE_TEMPLATE/1-feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/2-bug_report.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/2-bug_report.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 16de843..3ba13e0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1 @@ -blank_issues_enabled: true -contact_links: - - name: Ask a question - url: ../../../discussions - about: Get help using discussions +blank_issues_enabled: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index abbb1d6..94a94f1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,12 @@ + + ## Summary ## Fulfills -* Closes #xx: Bug 1 -* Closes #xx: Bug 2 -* Closes #xx: Feature 1 -* Closes #xx: Feature 2 +* Closes #xx +* Closes #xx diff --git a/.github/SECURITY.md b/.github/SECURITY.md index c1e76dc..2e0a418 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,9 +1,5 @@ # Security Policy -## Overview - -Security threats are to receive priority attention and released asap. The source code itself should contain no passwords or user information. - ## Supported Versions | Version | Supported | @@ -12,4 +8,19 @@ Security threats are to receive priority attention and released asap. The source ## Reporting a Vulnerability -Create and fill out a private security advisory here, or email the repository owner. +Pick one of the following options you find ideal for the situation: + +* Use GitHub private vulnerability reporting for this repository. + +Please do not use public GitHub issues, discussions, or pull requests to report security vulnerabilities. + +When reporting a vulnerability, please include: + +- The project and version +- A description of the issue +- The potential impact +- Steps to reproduce +- Any relevant logs or screenshots +- Any suggestions + +If a report is validated, we may publish a GitHub Security Advisory once details are ready to share publicly. diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..0e729be --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,56 @@ +# Support + +If you encounter any issue using the project, please create an issue for the project. Make sure to refer to and follow the [code of conduct](CODE_OF_CONDUCT.md). + +# Environment Setup + +Ensure you understand the [contributing](CONTRIBUTING.md) requirements, then follow the instructions below relevant to your environment. + +## Mac Environment Recommended Setup + +1) Install Command Line Developer Tools via the Terminal: + A) Check if installed: ‘xcode-select -p’ + B) If not, run: ‘code-select —install’ + C) Verify git works: ‘git —version’ +2) Install [VS Code](https://code.visualstudio.com/docs/setup/mac) for development. +3) Install [Google Chrome](https://www.google.com/chrome) for debugging. +4) Clone the repository in the editor, then: + A) Install all recommended extensions for the project. + B) Follow all prompts for signing in/downloads. + C) To see build options, run from terminal: "./build/run.sh --help" + D) Verify project state by running from terminal: "./build/run.sh test" + +## Linux Environment Recommended Setup + +1) Install packages for: + A) [.NET frameworks](https://dotnet.microsoft.com/download) + B) [Mono](https://www.mono-project.com/download/stable/#download-lin) + C) [VS Code](https://code.visualstudio.com/docs/setup/linux) +2) Install [Google Chrome](https://www.google.com/chrome) for debugging. +3) Clone the repository in the editor, then: + A) Install all recommended extensions for the project. + B) Run from terminal: "chmod +x ./build/run.sh" + C) To see build options, run from terminal: "./build/run.sh --help" + D) Verify project state by running from terminal: "./build/run.sh test" + +## Windows Environment Optional Setup + +VS Code is still recommended (see above setups), but VS Community may be utilized instead: + +1) Install [VS Community](https://visualstudio.microsoft.com/vs/community) for development. +2) Clone the repository locally. +3) To see build options, run from cmd prompt: "./build/run.cmd --help" +4) Verify project state by running from cmd prompt: "./build/run.cmd test" + +## Git & GPG Quick Setup Example + +Set the following git configuration settings, replacing [xxx] with valid personal values: + +1) git config --global user.name "[xxx]" +2) git config --global user.email "[xxx]@users.noreply.github.com" +3) git config --global user.signingKey [xxx] +4) git config --global tag.gpgSign true +5) git config --global commit.gpgSign true +6) git config --global push.gpgSign "if-asked" + +Read more about GPG keys and why they must be set in the [contributing](CONTRIBUTING.md) requirements. diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml deleted file mode 100644 index d2710e3..0000000 --- a/.github/workflows/analysis.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Analysis - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - schedule: - - cron: '0 17 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'csharp' ] - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index befff67..158813c 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -1,46 +1,43 @@ name: Integration on: - workflow_dispatch: push: branches: [ main ] pull_request: branches: [ main ] jobs: - ubuntu: - runs-on: ubuntu-latest + testing: + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] + fail-fast: false + runs-on: ${{ matrix.os }} + timeout-minutes: 15 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v5 with: - dotnet-version: '7.0.x' + dotnet-version: 10.0.x - name: Build & Test run: ./build/run.sh test - - mac: - runs-on: macOS-latest - steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '7.0.x' - - name: Build & Test - run: bash build/run.sh test - - windows: - runs-on: windows-latest + shell: bash + + coverage: + runs-on: ubuntu-latest + timeout-minutes: 15 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v5 with: - dotnet-version: '7.0.x' - - name: Build & Test & Coverage - run: ./build/run.cmd test coverage - - name: Upload coverage - uses: codecov/codecov-action@v3 + dotnet-version: 10.0.x + - name: Build & Check Test Coverage + shell: bash + run: ./build/run.sh coverage + - name: Upload Coverage + uses: codecov/codecov-action@v6 with: directory: ./artifacts/coverage + token: ${{ Secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index edb759d..ea1a12c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,6 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files @@ -23,6 +9,7 @@ *.user *.userosscache *.sln.docstates +*.env # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs @@ -35,17 +22,37 @@ mono_crash.* [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -x64/ -x86/ + +[Dd]ebug/x64/ +[Dd]ebugPublic/x64/ +[Rr]elease/x64/ +[Rr]eleases/x64/ +bin/x64/ +obj/x64/ + +[Dd]ebug/x86/ +[Dd]ebugPublic/x86/ +[Rr]elease/x86/ +[Rr]eleases/x86/ +bin/x86/ +obj/x86/ + [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ +[Aa][Rr][Mm]64[Ee][Cc]/ bld/ -[Bb]in/ [Oo]bj/ +[Oo]ut/ [Ll]og/ [Ll]ogs/ +# Build results on 'Bin' directories +**/[Bb]in/* +# Uncomment if you have tasks that rely on *.refresh files to move binaries +# (https://github.com/github/gitignore/pull/3736) +#!**/[Bb]in/*.refresh + # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot @@ -57,12 +64,16 @@ Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +*.trx # NUnit *.VisualState.xml TestResult.xml nunit-*.xml +# Approval Tests result files +*.received.* + # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ @@ -75,6 +86,7 @@ BenchmarkDotNet.Artifacts/ project.lock.json project.fragment.lock.json artifacts/ +.artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt @@ -89,6 +101,7 @@ StyleCopReport.xml *.ilk *.meta *.obj +*.idb *.iobj *.pch *.pdb @@ -96,6 +109,8 @@ StyleCopReport.xml *.pgc *.pgd *.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp *.sbr *.tlb *.tli @@ -167,6 +182,7 @@ coverage*.info # NCrunch _NCrunch_* +.NCrunch_* .*crunch*.local.xml nCrunchTemp_* @@ -308,9 +324,6 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - # Visual Studio 6 workspace and project file (working project files containing files to include in project) *.dsw *.dsp @@ -328,22 +341,22 @@ node_modules/ _Pvt_Extensions # Paket dependency manager -.paket/paket.exe +**/.paket/paket.exe paket-files/ # FAKE - F# Make -.fake/ +**/.fake/ # CodeRush personal settings -.cr/personal +**/.cr/personal # Python Tools for Visual Studio (PTVS) -__pycache__/ +**/__pycache__/ *.pyc # Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config +#tools/** +#!tools/packages.config # Tabs Studio *.tss @@ -365,15 +378,19 @@ ASALocalRun/ # MSBuild Binary and Structured Log *.binlog +MSBuild_Logs/ + +# AWS SAM Build and Temporary Artifacts folder +.aws-sam # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder -.mfractor/ +**/.mfractor/ # Local History for Visual Studio -.localhistory/ +**/.localhistory/ # Visual Studio History (VSHistory) files .vshistory/ @@ -385,7 +402,7 @@ healthchecksdb MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder -.ionide/ +**/.ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd @@ -396,11 +413,14 @@ FodyWeavers.xsd !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json -*.code-workspace +!.vscode/*.code-snippets # Local History for Visual Studio Code .history/ +# Built Visual Studio Code Extensions +*.vsix + # Windows Installer files from build outputs *.cab *.msi @@ -409,4 +429,7 @@ FodyWeavers.xsd *.msp # JetBrains Rider -*.sln.iml \ No newline at end of file +*.sln.iml + +# Mac +*.DS_Store diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..f7b3c04 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "ms-dotnettools.csdevkit", + "editorconfig.editorconfig", + "streetsidesoftware.code-spell-checker", + "csharpier.csharpier-vscode" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index aadb748..2d13b05 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,12 +2,11 @@ "version": "0.2.0", "configurations": [ { - // https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "name": ".NET Core Launch (console)", + "name": "Launch Console", "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceFolder}/artifacts/bin/Terminal/Debug/net6.0/Terminal.dll", + "program": "${workspaceFolder}/artifacts/bin/Terminal/Debug/net10.0/Terminal.dll", "args": [], "cwd": "${workspaceFolder}", "console": "integratedTerminal", diff --git a/.vscode/settings.json b/.vscode/settings.json index 913ab99..df65117 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,24 +1,51 @@ { "omnisharp.enableEditorConfigSupport": true, - "omnisharp.enableRoslynAnalyzers": true, + "dotnet.formatting.organizeImportsOnFormat": true, + "dotnet.testWindow.enableTestExplorerDiff": false, + "dotnet.unitTests.runSettingsPath": "./tests/TestSettings.runsettings", + "dotnet.defaultSolution": "UltimateProjectStarter.slnx", + "git.enableSmartCommit": true, "git.enableCommitSigning": true, "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, "editor.rulers": [ - 120, - 140 + 120 ], + "[csharp]": { + "editor.defaultFormatter": "csharpier.csharpier-vscode" + }, + "[xml]": { + "editor.defaultFormatter": "csharpier.csharpier-vscode" + }, "cSpell.words": [ + "Analyser", "autobuild", "cobertura", "codecov", "codeql", "cref", "globaltool", + "Lindhart", + "Meziantou", "msbuild", "Randomizer", "reportgenerator", + "Roslynator", + "runsettings", "signoff", "targetdir", + "Werecodent", "xunit" - ] + ], + "cSpell.ignorePaths": [ + "**/usr/local/share/dotnet", + "**/var/folders/", + ".gitignore", + ".editorconfig", + ".vscode/", + "nuget.config", + "artifacts/" + ], } \ No newline at end of file diff --git a/CodeTemplate.sln b/CodeTemplate.sln deleted file mode 100644 index 5f9ef51..0000000 --- a/CodeTemplate.sln +++ /dev/null @@ -1,57 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{378B6633-003C-4424-B0A8-680C3A579CF0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library", "src\Library\Library.csproj", "{AB41ACBF-B02C-4F25-884A-90EDE7052BA0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal", "src\Terminal\Terminal.csproj", "{7947D67A-A5E8-4BCF-A292-B90DCEE02346}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{84BCB816-4480-4B6B-99ED-B28E5B40DB97}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryTests", "tests\LibraryTests\LibraryTests.csproj", "{C983877A-56E5-459D-BBF8-DF75C25BA2C1}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerminalTests", "tests\TerminalTests\TerminalTests.csproj", "{D13BE3E4-EDC5-449F-8EB2-012B15555307}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "src\Build\Build.csproj", "{F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {AB41ACBF-B02C-4F25-884A-90EDE7052BA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AB41ACBF-B02C-4F25-884A-90EDE7052BA0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB41ACBF-B02C-4F25-884A-90EDE7052BA0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AB41ACBF-B02C-4F25-884A-90EDE7052BA0}.Release|Any CPU.Build.0 = Release|Any CPU - {7947D67A-A5E8-4BCF-A292-B90DCEE02346}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7947D67A-A5E8-4BCF-A292-B90DCEE02346}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7947D67A-A5E8-4BCF-A292-B90DCEE02346}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7947D67A-A5E8-4BCF-A292-B90DCEE02346}.Release|Any CPU.Build.0 = Release|Any CPU - {C983877A-56E5-459D-BBF8-DF75C25BA2C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C983877A-56E5-459D-BBF8-DF75C25BA2C1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C983877A-56E5-459D-BBF8-DF75C25BA2C1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C983877A-56E5-459D-BBF8-DF75C25BA2C1}.Release|Any CPU.Build.0 = Release|Any CPU - {D13BE3E4-EDC5-449F-8EB2-012B15555307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D13BE3E4-EDC5-449F-8EB2-012B15555307}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D13BE3E4-EDC5-449F-8EB2-012B15555307}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D13BE3E4-EDC5-449F-8EB2-012B15555307}.Release|Any CPU.Build.0 = Release|Any CPU - {F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {AB41ACBF-B02C-4F25-884A-90EDE7052BA0} = {378B6633-003C-4424-B0A8-680C3A579CF0} - {7947D67A-A5E8-4BCF-A292-B90DCEE02346} = {378B6633-003C-4424-B0A8-680C3A579CF0} - {C983877A-56E5-459D-BBF8-DF75C25BA2C1} = {84BCB816-4480-4B6B-99ED-B28E5B40DB97} - {D13BE3E4-EDC5-449F-8EB2-012B15555307} = {84BCB816-4480-4B6B-99ED-B28E5B40DB97} - {F6F3AE11-AEB0-4718-A414-E4BDC2CE79B6} = {378B6633-003C-4424-B0A8-680C3A579CF0} - EndGlobalSection -EndGlobal diff --git a/README.md b/README.md index c84cb8c..cb04f0f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,30 @@ -# Code Template +# Ultimate Project Starter -[![Build](https://github.com/GameCache/CodeTemplate/workflows/Integration/badge.svg)](../../actions?query=workflow%3AIntegration) [![CodeCov Coverage](https://codecov.io/gh/GameCache/CodeTemplate/branch/main/graph/badge.svg)](https://codecov.io/gh/GameCache/CodeTemplate/branch/main) +[![Build](https://github.com/Werecodent/UltimateProjectStarter/actions/workflows/integration.yml/badge.svg?branch=main)](https://github.com/Werecodent/UltimateProjectStarter/actions/workflows/integration.yml) +[![CodeCov Coverage](https://codecov.io/gh/Werecodent/UltimateProjectStarter/branch/main/graph/badge.svg)](https://codecov.io/gh/Werecodent/UltimateProjectStarter/branch/main) -Quick template to start C# projects with. View the [documentation site](https://gamecache.github.io/CodeTemplate/) for instructions and more. +(This project is under construction at the moment; be cautious of incomplete instructions.) + +Everything you need to get a quick start for a C# project on GitHub! Useful as a template, a few find+replace actions and you're immediately ready to go, or just a useful reference. Contains: + +1) All the special GitHub project files to make your project polished. +2) A variety of sample projects to fit whatever you want to do. +3) Build workflows with test coverage collection. +4) Clean project structure with all output directed to './artifacts'. +5) Even the start of a [documentation site](https://Werecodent.github.io/UltimateProjectStarter/) using GitHub pages. + +## Instructions + +Customize the project for your own use by following these steps: + +1) Replace all instance of "Werecodent" with your organization's name (or empty). +2) Replace all instances of "UltimateProjectStarter" with your project's name. +3) Install "CodeCov" as a GitHub app to the project/organization and set it up, or remove all references. +4) Tweak existing code as needed and begin coding. ## Documentation -The documentation site is located here: https://gamecache.github.io/CodeTemplate/ +The documentation site is located here: https://Werecodent.github.io/UltimateProjectStarter/ The raw files can be viewed from the [docs](docs) folder or built into a local site using Jekyll. @@ -23,8 +41,11 @@ View the [license](LICENSE) file for more details. ## Acknowledgments * [CreateAndFake](https://github.com/CreateAndFake/CreateAndFake): For testing behavior. -* [xUnit](https://xunit.github.io/): For running tests. -* [Coverlet](https://github.com/tonerdo/coverlet) + [ReportGenerator](https://danielpalme.github.io/ReportGenerator/) + [CodeCov](https://codecov.io/): For test coverage. +* [xUnit](https://github.com/xunit/xunit) + [bUnit](https://bunit.dev): For running tests. +* [Coverlet](https://github.com/tonerdo/coverlet) + [ReportGenerator](https://danielpalme.github.io/ReportGenerator) + [CodeCov](https://codecov.io): For test coverage. * [Bullseye](https://github.com/adamralph/bullseye) + [SimpleExec](https://github.com/adamralph/simple-exec) + [MinVer](https://github.com/adamralph/minver): For project building. -* [GitHub](https://github.com/): For hosting code. -* [Microsoft](https://visualstudio.microsoft.com/vs/features/net-development/): For C# and editors. +* [AsyncFixer](https://github.com/semihokur/AsyncFixer) + [MissingAwaitWarning](https://github.com/ykoksen/unused-task-warning) + [Meziantou.Analyzer](https://github.com/meziantou/Meziantou.Analyzer) + [Sonar](https://github.com/SonarSource/sonar-dotnet): For code analyzers. +* [CSharpier](https://github.com/belav/csharpier): For formatting code. +* [GitHub](https://github.com): For hosting code. +* [Microsoft](https://visualstudio.microsoft.com/vs/features/net-development): For C# and editors. + diff --git a/UltimateProjectStarter.slnx b/UltimateProjectStarter.slnx new file mode 100644 index 0000000..ab2f5bf --- /dev/null +++ b/UltimateProjectStarter.slnx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/_config.yml b/docs/_config.yml index ded2648..3946269 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,5 +2,5 @@ theme: jekyll-theme-architect markdown: kramdown highlighter: rouge -title: CodeTemplate +title: UltimateProjectStarter description: Quick template to start C# projects with. diff --git a/docs/index.md b/docs/index.md index fea1df7..dd895f7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +1,3 @@ -# Getting Started +# About -Welcome to the documentation source for developers. - -## Quick Start - -1) Clone the repository. -2) Delete .git folder (hidden folder at root.) -3) Replace all instances of "CodeTemplate" with your project's name. -4) Delete the root .sln and [create your own](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-sln). -5) Tweak existing code as needed and begin coding. \ No newline at end of file +Welcome to the documentation source for developers. This is the homepage. diff --git a/docs/pages/General-Structure.md b/docs/pages/General-Structure.md index b31a2f9..0067c76 100644 --- a/docs/pages/General-Structure.md +++ b/docs/pages/General-Structure.md @@ -1,5 +1,7 @@ # Structure +Here's an example page. + This project template aims to be as clear as possible with minimal root noise. ## ./artifacts @@ -12,4 +14,4 @@ Contains common build properties and dependencies shared among all child project ## .editorconfig -Contains rules for all child projects/folders. Instances under src & tests generally contain analyzer settings. \ No newline at end of file +Contains rules for all child projects/folders. Instances under src & tests generally contain analyzer settings. diff --git a/src/.csharpierignore b/src/.csharpierignore new file mode 100644 index 0000000..5000514 --- /dev/null +++ b/src/.csharpierignore @@ -0,0 +1,2 @@ +**/*.csproj +**/Directory.Build.props diff --git a/src/.editorconfig b/src/.editorconfig index 8eb487a..d9fa0e8 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -1,27 +1,8 @@ [*.cs] -# Default severity for all analyzer diagnostics -dotnet_analyzer_diagnostic.severity = warning +# False positive when adding a tag while also using tag. +dotnet_diagnostic.CS1573.severity = None -# IDE0011: Add braces -csharp_prefer_braces = when_multiline:warning - -# CA1032: Implement standard exception constructors -dotnet_diagnostic.CA1032.severity = none -# CA1508: Avoid dead conditional code -dotnet_diagnostic.CA1508.severity = silent -# CA1805: Do not initialize unnecessarily -dotnet_diagnostic.CA1805.severity = none - -# IDE0045: 'if' statement can be simplified -dotnet_diagnostic.IDE0045.severity = none -# IDE0046: Convert to conditional expression -dotnet_diagnostic.IDE0046.severity = none -# IDE0047: Remove unnecessary parentheses -dotnet_diagnostic.IDE0047.severity = none -# IDE0048: Add parentheses for clarity -dotnet_diagnostic.IDE0048.severity = none -# IDE0063: 'using' statement can be simplified -dotnet_diagnostic.IDE0063.severity = none -# IDE0079: Remove unnecessary suppression -dotnet_diagnostic.IDE0079.severity = none +# Bad rules that advocate for less maintainable documentation. +dotnet_diagnostic.MA0197.severity = None +dotnet_diagnostic.MA0203.severity = None diff --git a/src/Build/.editorconfig b/src/Build/.editorconfig index b5bcf17..a352f28 100644 --- a/src/Build/.editorconfig +++ b/src/Build/.editorconfig @@ -1,4 +1,4 @@ [*.cs] -# Consider calling ConfigureAwait on the awaited task -dotnet_diagnostic.CA2007.severity = none; +# Not needed for the build project. +dotnet_diagnostic.CA2007.severity = None diff --git a/src/Build/Build.csproj b/src/Build/Build.csproj index c38e370..a31310b 100644 --- a/src/Build/Build.csproj +++ b/src/Build/Build.csproj @@ -1,14 +1,15 @@ - net7.0 - Exe + net10.0 + exe false + $(MSBuildProjectName) - - + + - \ No newline at end of file + diff --git a/src/Build/Program.cs b/src/Build/Program.cs index 902b289..cdf94f6 100644 --- a/src/Build/Program.cs +++ b/src/Build/Program.cs @@ -1,95 +1,146 @@ -using System.IO; -using System.Threading.Tasks; -using static Bullseye.Targets; -using static SimpleExec.Command; - -namespace CodeTemplate.Build -{ - /// Manages build behavior for the solution. - public static class Program - { - /// Base directory for all output. - private static readonly string _ArtifactDir = Path.Combine(Directory.GetCurrentDirectory(), "artifacts"); - - /// Console application entry point. - public static async Task Main(string[] args) - { - Target("default", DependsOn("coverage")); - Target("restore", Restore); - Target("compile", DependsOn("restore"), Compile); - Target("runConsole", DependsOn("compile"), RunConsole); - Target("test", DependsOn("compile"), Test); - Target("coverage", DependsOn("compile"), Coverage); - await RunTargetsAndExitAsync(args); - } - - /// Downloads all packages for the solution. - private static Task Restore() - { - return RunAsync("dotnet", "restore"); - } - - /// Builds the solution. - private static async Task Compile() - { - await RunAsync($"dotnet", $"build --no-restore --configuration Debug"); - await RunAsync($"dotnet", $"build --no-restore --configuration Release"); - } - - /// Runs the console version. - private static async Task RunConsole() - { - await RunAsync($"dotnet", $"run src/Terminal --no-restore --no-build --configuration Release"); - } - - /// Tests the solution. - private static async Task Test() - { - string testArgs = "test --no-restore --no-build "; - - await RunAsync("dotnet", testArgs + "--configuration Debug"); - await RunAsync("dotnet", testArgs + "--configuration Release"); - } - - /// Tests and analyzes test code coverage. - private static async Task Coverage() - { - string prefix = "coverage"; - string postfix = ".cobertura.xml"; - - string coverageDir = Path.Combine(_ArtifactDir, "coverage"); - string testDir = Path.Combine(coverageDir, "testResults"); - string reportDir = Path.Combine(coverageDir, "report"); - - EnsureEmpty(coverageDir); - - await RunAsync("dotnet", string.Join(' ', - "test", - "--no-build", - "--no-restore", - "--configuration Debug", - "--collect:\"XPlat Code Coverage\"", - $"--results-directory \"{testDir}\"")); - - int count = 0; - foreach (string result in Directory.GetFiles(testDir, $"{prefix}{postfix}", SearchOption.AllDirectories)) - { - File.Copy(result, Path.Combine(coverageDir, $"{prefix}{count++}{postfix}")); - } - - await RunAsync("dotnet", "tool update -g dotnet-reportgenerator-globaltool"); - await RunAsync("reportgenerator", $"-reports:{coverageDir}/*.xml -targetdir:{reportDir}"); - } - - /// Deletes and creates a directory. - /// Directory to empty. - private static void EnsureEmpty(string dir) - { - if (Directory.Exists(dir)) - { - Directory.Delete(dir, true); - } - _ = Directory.CreateDirectory(dir); - } - } -} +using static Bullseye.Targets; +using static SimpleExec.Command; + +namespace Build; + +/// Manages build behavior for the solution. +/// Do not add this project to the solution file. +internal static class Program +{ + /// Base directory for all output. + private static readonly string _ArtifactDir = Path.Combine( + Directory.GetCurrentDirectory(), + "artifacts" + ); + + /// Console application entry point. + /// Command-line arguments. + public static Task Main(string[] args) + { + string[] configurations = ["Debug", "Release"]; + Target("default", dependsOn: ["test"]); + Target("restore", RestoreAsync); + Target("compile", dependsOn: ["restore"], forEach: configurations, CompileAsync); + Target("test", dependsOn: ["compile"], forEach: configurations, TestAsync); + Target("coverage", dependsOn: ["compile"], CoverageAsync); + Target("pack", dependsOn: ["compile"], PackAsync); + Target("debugCrash", dependsOn: ["compile"], DebugCrashAsync); + return RunTargetsAndExitAsync(args); + } + + /// Downloads all packages for the solution. + private static async Task RestoreAsync() + { + await RunAsync("dotnet", "tool update -g csharpier").ConfigureAwait(false); + await RunAsync("dotnet", "restore").ConfigureAwait(false); + } + + /// Builds the solution. + /// Build configuration to use. + private static Task CompileAsync(string configuration) + { + return RunAsync("dotnet", $"build --no-restore --configuration {configuration}"); + } + + /// Tests the solution. + /// Build configuration to use. + private static Task TestAsync(string configuration) + { + return RunAsync("dotnet", $"test --no-restore --no-build --configuration {configuration}"); + } + + /// Tests the solution with file logging. + /// For debugging test harness crashes. + private static Task DebugCrashAsync() + { + string logDir = Path.Combine(_ArtifactDir, "logs"); + EnsureEmpty(logDir); + + string logFile = Path.Combine(logDir, "test.txt"); + string testArgs = $"test --no-restore --no-build --diag:{logFile} "; + + return RunAsync("dotnet", testArgs + "--configuration Debug"); + } + + /// Tests and analyzes test code coverage. + private static async Task CoverageAsync() + { + const string prefix = "coverage"; + const string postfix = ".cobertura.xml"; + + string toolsDir = Path.Combine(_ArtifactDir, "tools"); + string coverageDir = Path.Combine(_ArtifactDir, "coverage"); + string testDir = Path.Combine(coverageDir, "testResults"); + string reportDir = Path.Combine(coverageDir, "report"); + + EnsureEmpty(coverageDir); + + await RunAsync( + "dotnet", + string.Join( + ' ', + "test", + "--no-build", + "--no-restore", + "--configuration Debug", + "--collect:\"XPlat Code Coverage\"", + $"--results-directory \"{testDir}\"" + ) + ) + .ConfigureAwait(false); + + int count = 0; + foreach ( + string result in Directory.GetFiles( + testDir, + prefix + postfix, + SearchOption.AllDirectories + ) + ) + { + File.Copy(result, Path.Combine(coverageDir, $"{prefix}{count++}{postfix}")); + } + + await RunAsync( + "dotnet", + $"tool update dotnet-reportgenerator-globaltool --tool-path {toolsDir}" + ) + .ConfigureAwait(false); + await RunAsync( + $"{toolsDir}/reportgenerator", + $"-reports:{coverageDir}/*.xml -targetdir:{reportDir}" + ) + .ConfigureAwait(false); + } + + /// Packs the solution for release. + private static Task PackAsync() + { + string releaseDir = Path.Combine(_ArtifactDir, "releases"); + EnsureEmpty(releaseDir); + + return RunAsync( + "dotnet", + string.Join( + ' ', + "pack", + "--no-build", + "--no-restore", + "--configuration Release", + $"--output \"{releaseDir}\"" + ) + ); + } + + /// Enforces that exists and is empty. + /// Directory to empty/create. + /// Any existing contents are deleted. + private static void EnsureEmpty(string dir) + { + if (Directory.Exists(dir)) + { + Directory.Delete(dir, true); + } + _ = Directory.CreateDirectory(dir); + } +} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d252c2e..167bb74 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,19 +2,37 @@ latest enable + enable true - AllEnabledByDefault + All true - CodeTemplate.$(MSBuildProjectName) - $(MSBuildThisFileDirectory)..\artifacts\obj\$(MSBuildProjectName)\ - $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\ - $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).xml + Werecodent.UltimateProjectStarter.$(MSBuildProjectName) v + + + true + $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).xml + $(MSBuildThisFileDirectory)..\artifacts\obj\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\ + false + + - - + + + + + + + + + + + + <_Parameter1>true @@ -23,7 +41,7 @@ <_Parameter1>FakerTypes - <_Parameter1>$(MSBuildProjectName)Tests + <_Parameter1>$(MSBuildProjectName).Tests - \ No newline at end of file + diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index 5f6d7ce..2808c48 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,7 +1,5 @@  - - net7.0 + net10.0 - - \ No newline at end of file + diff --git a/src/Library/TextChecker.cs b/src/Library/TextChecker.cs index 09456e1..ad5c065 100644 --- a/src/Library/TextChecker.cs +++ b/src/Library/TextChecker.cs @@ -1,19 +1,13 @@ -using System.Text.RegularExpressions; - -namespace CodeTemplate.Library -{ - /// Verifies string contents. - public static partial class TextChecker - { - [GeneratedRegex(@"^[\w\d]+$", RegexOptions.CultureInvariant)] - private static partial Regex NumbersAndLettersRegex(); - - /// Verifies input only has numbers and letters. - /// String to check. - /// True if valid; false otherwise. - public static bool IsOnlyNumbersAndLetters(string input) - { - return NumbersAndLettersRegex().IsMatch(input); - } - } -} +namespace Werecodent.UltimateProjectStarter.Library; + +/// Verifies string contents. +public static class TextChecker +{ + /// Verifies input only has numbers and letters. + /// String to check. + /// True if valid; false otherwise. + public static bool IsOnlyNumbersAndLetters(string input) + { + return input.All(char.IsLetterOrDigit); + } +} diff --git a/src/Terminal/Program.cs b/src/Terminal/Program.cs index d53a981..d895243 100644 --- a/src/Terminal/Program.cs +++ b/src/Terminal/Program.cs @@ -1,30 +1,28 @@ -using System; -using CodeTemplate.Library; - -namespace CodeTemplate.Terminal -{ - /// Handles running chess on the console. - public static class Program - { - /// Application entry point. - public static void Main() - { - while (true) - { - string input = Console.ReadLine() ?? "quit"; - if (TextChecker.IsOnlyNumbersAndLetters(input)) - { - switch (input) - { - default: - Console.WriteLine(input); - break; - case "quit": - case "q": - return; - } - } - } - } - } -} +using Werecodent.UltimateProjectStarter.Library; + +namespace Werecodent.UltimateProjectStarter.Terminal; + +/// Handles running chess on the console. +internal static class Program +{ + /// Application entry point. + public static void Main() + { + while (true) + { + string input = Console.ReadLine() ?? "quit"; + if (TextChecker.IsOnlyNumbersAndLetters(input)) + { + switch (input) + { + default: + Console.WriteLine(input); + break; + case "quit": + case "q": + return; + } + } + } + } +} diff --git a/src/Terminal/Terminal.csproj b/src/Terminal/Terminal.csproj index 5ba2ba4..5d9aa54 100644 --- a/src/Terminal/Terminal.csproj +++ b/src/Terminal/Terminal.csproj @@ -1,12 +1,10 @@ - Exe - net7.0 + net10.0 - diff --git a/tests/.csharpierignore b/tests/.csharpierignore new file mode 100644 index 0000000..5000514 --- /dev/null +++ b/tests/.csharpierignore @@ -0,0 +1,2 @@ +**/*.csproj +**/Directory.Build.props diff --git a/tests/.editorconfig b/tests/.editorconfig index a4942b5..1f2a912 100644 --- a/tests/.editorconfig +++ b/tests/.editorconfig @@ -1,34 +1,31 @@ [*.cs] -# Default severity for all analyzer diagnostics -dotnet_analyzer_diagnostic.severity = warning +# Needed for testing and cleaner tests. +dotnet_diagnostic.CA1002.severity = None +dotnet_diagnostic.CA1034.severity = None +dotnet_diagnostic.CA1044.severity = None +dotnet_diagnostic.CA1051.severity = None +dotnet_diagnostic.CA1515.severity = None +dotnet_diagnostic.CA1812.severity = None +dotnet_diagnostic.CA2263.severity = None +dotnet_diagnostic.MA0016.severity = None -# IDE0011: Add braces -csharp_prefer_braces = when_multiline:warning +# Unnecessary for tests. +dotnet_diagnostic.CA1062.severity = None +dotnet_diagnostic.CS1591.severity = None +dotnet_diagnostic.VSTHRD200.severity = None -# CA1034: Nested types should not be visible -dotnet_diagnostic.CA1034.severity = none -# CA1307: Specify StringComparison for clarity -dotnet_diagnostic.CA1307.severity = none -# CA1707: Identifiers should not contain underscores -dotnet_diagnostic.CA1707.severity = none -# CA1812: Avoid uninstantiated internal classes -dotnet_diagnostic.CA1812.severity = none -# CA1805: Do not initialize unnecessarily -dotnet_diagnostic.CA1805.severity = none +# Noise when using fluent APIs. +dotnet_diagnostic.IDE0058.severity = None -# CS1591: Missing XML comment for publicaly visible -dotnet_diagnostic.CS1591.severity = none +# Default of .ConfigureAwait(true) for tests is proper. +dotnet_diagnostic.CA2007.severity = None +dotnet_diagnostic.MA0004.severity = None +dotnet_diagnostic.VSTHRD111.severity = None -# IDE0046: 'if' statement can be simplified -dotnet_diagnostic.IDE0046.severity = none -# IDE0047: Remove unnecessary parentheses -dotnet_diagnostic.IDE0047.severity = none -# IDE0048: Add parentheses for clarity -dotnet_diagnostic.IDE0048.severity = none -# IDE0063: Use simple 'using' statement -dotnet_diagnostic.IDE0063.severity = none -# IDE0058: Expression value is never used -dotnet_diagnostic.IDE0058.severity = none -# IDE0079: Remove unnecessary suppression -dotnet_diagnostic.IDE0079.severity = none +# Conflict for test name matching. +dotnet_diagnostic.CA1707.severity = None +dotnet_diagnostic.MA0048.severity = None + +# False positive when calling tester methods. +dotnet_diagnostic.S2699.severity = None diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 86859ad..907fa5c 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -2,25 +2,44 @@ latest enable + enable true - AllEnabledByDefault + All true - CodeTemplate.$(MSBuildProjectName) - $(MSBuildThisFileDirectory)..\artifacts\obj\$(MSBuildProjectName)\ - $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\ + false + Werecodent.UltimateProjectStarter.$(MSBuildProjectName) + + + + true $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\$(TargetFramework)\$(MSBuildProjectName).xml + $(MSBuildThisFileDirectory)..\artifacts\obj\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName) + $(MSBuildThisFileDirectory)..\artifacts\bin\$(MSBuildProjectName)\$(Configuration)\ $(MSBuildThisFileDirectory)TestSettings.runsettings true - false + true + - - - - - - + + + + + + + + + + + + + + + + + <_Parameter1>true @@ -29,4 +48,8 @@ <_Parameter1>FakerTypes - \ No newline at end of file + + + + + diff --git a/tests/LibraryTests/LibraryTests.csproj b/tests/Library.Tests/Library.Tests.csproj similarity index 79% rename from tests/LibraryTests/LibraryTests.csproj rename to tests/Library.Tests/Library.Tests.csproj index 0d505ef..6cdcd7d 100644 --- a/tests/LibraryTests/LibraryTests.csproj +++ b/tests/Library.Tests/Library.Tests.csproj @@ -1,11 +1,9 @@  - - net7.0 + net10.0 - diff --git a/tests/Library.Tests/TextCheckerTests.cs b/tests/Library.Tests/TextCheckerTests.cs new file mode 100644 index 0000000..3ad4446 --- /dev/null +++ b/tests/Library.Tests/TextCheckerTests.cs @@ -0,0 +1,31 @@ +using System.Globalization; +using CreateAndFake; +using CreateAndFake.Fluent; +using Xunit; + +namespace Werecodent.UltimateProjectStarter.Library.Tests; + +public static class TextCheckerTests +{ + [Fact] + internal static void IsOnlyNumbersAndLetters_MatchesNumbers() + { + int value = Math.Abs(Tools.Randomizer.Create()); + TextChecker + .IsOnlyNumbersAndLetters(value.ToString(CultureInfo.InvariantCulture)) + .Assert() + .Is(true); + } + + [Fact] + internal static void IsOnlyNumbersAndLetters_MatchesText() + { + TextChecker.IsOnlyNumbersAndLetters("message").Assert().Is(true); + } + + [Fact] + internal static void IsOnlyNumbersAndLetters_NotMatchesSymbols() + { + TextChecker.IsOnlyNumbersAndLetters("$test").Assert().Is(false); + } +} diff --git a/tests/LibraryTests/TextCheckerTests.cs b/tests/LibraryTests/TextCheckerTests.cs deleted file mode 100644 index 43ba33b..0000000 --- a/tests/LibraryTests/TextCheckerTests.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Globalization; -using CodeTemplate.Library; -using CreateAndFake; -using CreateAndFake.Fluent; -using Xunit; - -namespace CodeTemplate.LibraryTests -{ - public static class TextCheckerTests - { - [Fact] - internal static void IsOnlyNumbersAndLetters_MatchesNumbers() - { - int value = Math.Abs(Tools.Randomizer.Create()); - TextChecker - .IsOnlyNumbersAndLetters(value.ToString(CultureInfo.InvariantCulture)) - .Assert() - .Is(true); - } - - [Fact] - internal static void IsOnlyNumbersAndLetters_MatchesText() - { - TextChecker - .IsOnlyNumbersAndLetters("message") - .Assert() - .Is(true); - } - - [Fact] - internal static void IsOnlyNumbersAndLetters_NotMatchesSymbols() - { - TextChecker - .IsOnlyNumbersAndLetters("$test") - .Assert() - .Is(false); - } - } -} diff --git a/tests/Terminal.Tests/ProgramTests.cs b/tests/Terminal.Tests/ProgramTests.cs new file mode 100644 index 0000000..8462087 --- /dev/null +++ b/tests/Terminal.Tests/ProgramTests.cs @@ -0,0 +1,41 @@ +using CreateAndFake.Fluent; +using Xunit; + +namespace Werecodent.UltimateProjectStarter.Terminal.Tests; + +public static class ProgramTests +{ + [Fact] + internal static void Main_Runs() + { + using StringReader input = new( + string.Join(Environment.NewLine, "test", "$yo", null, "quit") + ); + Console.SetIn(input); + + using StringWriter output = new(); + Console.SetOut(output); + + Program.Main(); + + string result = output.ToString(); + result.Assert().Contains("test"); + result.Assert().ContainsNot("$yo"); + } + + [Fact] + internal static void Main_EndOfInputTerminates() + { + using StringReader input = new(string.Join(Environment.NewLine, "test", "test2")); + Console.SetIn(input); + + using StringWriter output = new(); + Console.SetOut(output); + + Program.Main(); + + string result = output.ToString(); + result.Assert().Contains("test"); + result.Assert().Contains("test2"); + } +} diff --git a/tests/TerminalTests/TerminalTests.csproj b/tests/Terminal.Tests/Terminal.Tests.csproj similarity index 79% rename from tests/TerminalTests/TerminalTests.csproj rename to tests/Terminal.Tests/Terminal.Tests.csproj index 7083cdf..0e0d716 100644 --- a/tests/TerminalTests/TerminalTests.csproj +++ b/tests/Terminal.Tests/Terminal.Tests.csproj @@ -1,11 +1,9 @@ - - net7.0 + net10.0 - diff --git a/tests/TerminalTests/ProgramTests.cs b/tests/TerminalTests/ProgramTests.cs deleted file mode 100644 index 9a439b9..0000000 --- a/tests/TerminalTests/ProgramTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.IO; -using CodeTemplate.Terminal; -using CreateAndFake.Fluent; -using Xunit; - -namespace CodeTemplate.TerminalTests -{ - public static class ProgramTests - { - [Fact] - internal static void Main_Runs() - { - using StringReader input = new(string.Join(Environment.NewLine, "test", "$yo", null, "quit")); - Console.SetIn(input); - - using StringWriter output = new(); - Console.SetOut(output); - - Program.Main(); - - string result = output.ToString(); - result.Assert().Contains("test"); - result.Assert().ContainsNot("$yo"); - } - - [Fact] - internal static void Main_EndOfInputTerminates() - { - using StringReader input = new(string.Join(Environment.NewLine, "test", "test2")); - Console.SetIn(input); - - using StringWriter output = new(); - Console.SetOut(output); - - Program.Main(); - - string result = output.ToString(); - result.Assert().Contains("test"); - result.Assert().Contains("test2"); - } - } -} diff --git a/tests/TestSettings.runsettings b/tests/TestSettings.runsettings index db62968..ae7b360 100644 --- a/tests/TestSettings.runsettings +++ b/tests/TestSettings.runsettings @@ -2,5 +2,6 @@ ../artifacts/testing + 300000