diff --git a/404.html b/404.html index ba0c6fd212..85ff4641d7 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ Page Not Found | TUnit - + diff --git a/assets/js/12f8ba17.b11c3ad6.js b/assets/js/12f8ba17.630f595c.js similarity index 64% rename from assets/js/12f8ba17.b11c3ad6.js rename to assets/js/12f8ba17.630f595c.js index f4fed4d055..d98c1738ac 100644 --- a/assets/js/12f8ba17.b11c3ad6.js +++ b/assets/js/12f8ba17.630f595c.js @@ -1 +1 @@ -"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[8887],{511:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var n=s(4848),i=s(8453);const r={sidebar_position:7},o="Extensibility / Custom Assertions",a={id:"tutorial-assertions/extensibility",title:"Extensibility / Custom Assertions",description:"The TUnit Assertions can be easily extended so that you can create your own assertions.",source:"@site/docs/tutorial-assertions/extensibility.md",sourceDirName:"tutorial-assertions",slug:"/tutorial-assertions/extensibility",permalink:"/TUnit/docs/tutorial-assertions/extensibility",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7},sidebar:"tutorialSidebar",previous:{title:"Delegates",permalink:"/TUnit/docs/tutorial-assertions/delegates"},next:{title:"Congratulations",permalink:"/TUnit/docs/tutorial-assertions/congratulations"}},l={},c=[];function d(e){const t={code:"code",h1:"h1",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"extensibility--custom-assertions",children:"Extensibility / Custom Assertions"})}),"\n",(0,n.jsx)(t.p,{children:"The TUnit Assertions can be easily extended so that you can create your own assertions."}),"\n",(0,n.jsx)(t.p,{children:"In TUnit, there are two types of things we can assert on:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Values"}),"\n",(0,n.jsx)(t.li,{children:"Delegates"}),"\n"]}),"\n",(0,n.jsxs)(t.p,{children:["Values is what you'd guess, some return value, such as a ",(0,n.jsx)(t.code,{children:"string"})," or ",(0,n.jsx)(t.code,{children:"int"})," or even a complex class."]}),"\n",(0,n.jsxs)(t.p,{children:["Delegates are bits of code that haven't executed yet - Instead they are passed into the assertion builder, and the TUnit assertion library will execute it. If it throws, then there will be an ",(0,n.jsx)(t.code,{children:"Exception"})," object we can check in our assertion."]}),"\n",(0,n.jsx)(t.p,{children:"So to create a custom assertion:"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Create a class that inherits from ",(0,n.jsx)(t.code,{children:"AssertCondition"}),"\n",(0,n.jsx)(t.code,{children:"TActual"})," will the the type of object that is being asserted. For example if I started with ",(0,n.jsx)(t.code,{children:'Assert.That("Some text")'})," then ",(0,n.jsx)(t.code,{children:"TActual"})," would be a ",(0,n.jsx)(t.code,{children:"string"})," because that's what we're asserting on."]}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"TExpected"})," will be the data (if any) that you receive from your extension method, so you'll be responsible for passing this in. You must pass it to the base class via the base constructor: ",(0,n.jsx)(t.code,{children:"base(expectedValue)"})]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Override the method:\n",(0,n.jsx)(t.code,{children:"private protected override bool Passes(TActual? actualValue, Exception? exception)"})]}),"\n",(0,n.jsx)(t.p,{children:"If this method returns true, then your assertion has passed, if it returns false, then your exception will throw with the failure message that you specify."}),"\n",(0,n.jsxs)(t.p,{children:["To access ",(0,n.jsx)(t.code,{children:"TExpected"})," here, it's an accessible property called ",(0,n.jsx)(t.code,{children:"ExpectedValue"})]}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"Exception"})," object will be populated if your assertion is a Delegate type and the delegate threw."]}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"TActual"})," object will be populated if a value was passed into ",(0,n.jsx)(t.code,{children:"Assert.That(...)"}),", or a delegate with a return value was executed successfully."]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Override the ",(0,n.jsx)(t.code,{children:"GetFailureMessage"})," method to return a message when the assertion fails. While you're inside the ",(0,n.jsx)(t.code,{children:"Passes()"})," method you can also set an ",(0,n.jsx)(t.code,{children:"OverriddenMessage"})," string property that will take priority instead. This can be useful if you want to change the failure message dynamically. For example, the default is 'Expected x but received y' - But if one of the values is null, we want to change the message to 'No expected value was passed into the assertion'."]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Create the extension method!\nThis is where things can start to look daunting because of the generic constraints, but this allows chaining assertions together."}),"\n",(0,n.jsxs)(t.p,{children:["You need to create an extension off of either ",(0,n.jsx)(t.code,{children:"IValueSource"})," or ",(0,n.jsx)(t.code,{children:"IDelegateSource"})," - Depending on what you're planning to write an assertion for. By extending off of the relevant interface we make sure that it won't be shown where it doesn't make sense thanks to the C# typing system."]}),"\n",(0,n.jsxs)(t.p,{children:["Your return type for the extension method should be ",(0,n.jsx)(t.code,{children:"InvokableAssertionBuilder"})]}),"\n",(0,n.jsxs)(t.p,{children:["And then finally, you just new up your custom assert condition class, and then call the extension method ",(0,n.jsx)(t.code,{children:"ChainedTo(source.AssertionBuilder, [...argumentExpression])"})," on it, which will add it to our assertion builder. You don't have to worry what that's doing behind the scenes, it's just building rules that can chain together."]}),"\n",(0,n.jsxs)(t.p,{children:["The argument expression array allows you to pass in ",(0,n.jsx)(t.code,{children:"[CallerArgumentExpression]"})," values so that your assertion errors show you the code executed to give clear exception messages."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"Here's a fully fledged assertion in action:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-csharp",children:'public static InvokableAssertionBuilder Contains(this IValueSource valueSource, string expected, StringComparison stringComparison, [CallerArgumentExpression("expected")] string doNotPopulateThisValue1 = "", [CallerArgumentExpression("stringComparison")] string doNotPopulateThisValue2 = "")\n where TAnd : IAnd\n where TOr : IOr\n {\n return new StringContainsAssertCondition(expected, stringComparison)\n .ChainedTo(valueSource.AssertionBuilder, [doNotPopulateThisValue1, doNotPopulateThisValue2]);\n }\n'})}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-csharp",children:'public class StringContainsAssertCondition(string expected, StringComparison stringComparison)\n : AssertCondition(expected)\n{\n private protected override bool Passes(string? actualValue, Exception? exception)\n {\n if (actualValue is null)\n {\n OverriddenMessage = $"{ActualExpression ?? "Actual string"} is null";\n return false;\n }\n \n if (ExpectedValue is null)\n {\n OverriddenMessage = "No expected value given";\n return false;\n }\n \n return actualValue.Contains(ExpectedValue, stringComparison);\n }\n\n protected internal override string GetFailureMessage() => $"""\n Expected "{ActualValue}" to contain "{ExpectedValue}"\n """;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>a});var n=s(6540);const i={},r=n.createContext(i);function o(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunktunit_docs_site=self.webpackChunktunit_docs_site||[]).push([[8887],{511:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>a,toc:()=>c});var n=s(4848),i=s(8453);const r={sidebar_position:7},o="Extensibility / Custom Assertions",a={id:"tutorial-assertions/extensibility",title:"Extensibility / Custom Assertions",description:"The TUnit Assertions can be easily extended so that you can create your own assertions.",source:"@site/docs/tutorial-assertions/extensibility.md",sourceDirName:"tutorial-assertions",slug:"/tutorial-assertions/extensibility",permalink:"/TUnit/docs/tutorial-assertions/extensibility",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:7,frontMatter:{sidebar_position:7},sidebar:"tutorialSidebar",previous:{title:"Delegates",permalink:"/TUnit/docs/tutorial-assertions/delegates"},next:{title:"Congratulations",permalink:"/TUnit/docs/tutorial-assertions/congratulations"}},l={},c=[];function d(e){const t={code:"code",h1:"h1",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"extensibility--custom-assertions",children:"Extensibility / Custom Assertions"})}),"\n",(0,n.jsx)(t.p,{children:"The TUnit Assertions can be easily extended so that you can create your own assertions."}),"\n",(0,n.jsx)(t.p,{children:"In TUnit, there are two types of things we can assert on:"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"Values"}),"\n",(0,n.jsx)(t.li,{children:"Delegates"}),"\n"]}),"\n",(0,n.jsxs)(t.p,{children:["Values is what you'd guess, some return value, such as a ",(0,n.jsx)(t.code,{children:"string"})," or ",(0,n.jsx)(t.code,{children:"int"})," or even a complex class."]}),"\n",(0,n.jsxs)(t.p,{children:["Delegates are bits of code that haven't executed yet - Instead they are passed into the assertion builder, and the TUnit assertion library will execute it. If it throws, then there will be an ",(0,n.jsx)(t.code,{children:"Exception"})," object we can check in our assertion."]}),"\n",(0,n.jsx)(t.p,{children:"So to create a custom assertion:"}),"\n",(0,n.jsxs)(t.ol,{children:["\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Create a class that inherits from ",(0,n.jsx)(t.code,{children:"AssertCondition"}),"\n",(0,n.jsx)(t.code,{children:"TActual"})," will the the type of object that is being asserted. For example if I started with ",(0,n.jsx)(t.code,{children:'Assert.That("Some text")'})," then ",(0,n.jsx)(t.code,{children:"TActual"})," would be a ",(0,n.jsx)(t.code,{children:"string"})," because that's what we're asserting on."]}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"TExpected"})," will be the data (if any) that you receive from your extension method, so you'll be responsible for passing this in. You must pass it to the base class via the base constructor: ",(0,n.jsx)(t.code,{children:"base(expectedValue)"})]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Override the method:\n",(0,n.jsx)(t.code,{children:"private protected override bool Passes(TActual? actualValue, Exception? exception)"})]}),"\n",(0,n.jsx)(t.p,{children:"If this method returns true, then your assertion has passed, if it returns false, then your exception will throw with the failure message that you specify."}),"\n",(0,n.jsxs)(t.p,{children:["To access ",(0,n.jsx)(t.code,{children:"TExpected"})," here, it's an accessible property called ",(0,n.jsx)(t.code,{children:"ExpectedValue"})]}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"Exception"})," object will be populated if your assertion is a Delegate type and the delegate threw."]}),"\n",(0,n.jsxs)(t.p,{children:["The ",(0,n.jsx)(t.code,{children:"TActual"})," object will be populated if a value was passed into ",(0,n.jsx)(t.code,{children:"Assert.That(...)"}),", or a delegate with a return value was executed successfully."]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsxs)(t.p,{children:["Override the ",(0,n.jsx)(t.code,{children:"GetFailureMessage"})," method to return a message when the assertion fails. While you're inside the ",(0,n.jsx)(t.code,{children:"Passes()"})," method you can also set an ",(0,n.jsx)(t.code,{children:"OverriddenMessage"})," string property that will take priority instead. This can be useful if you want to change the failure message dynamically. For example, the default is 'Expected x but received y' - But if one of the values is null, we want to change the message to 'No expected value was passed into the assertion'."]}),"\n"]}),"\n",(0,n.jsxs)(t.li,{children:["\n",(0,n.jsx)(t.p,{children:"Create the extension method!\nThis is where things can start to look daunting because of the generic constraints, but this allows chaining assertions together."}),"\n",(0,n.jsxs)(t.p,{children:["You need to create an extension off of either ",(0,n.jsx)(t.code,{children:"IValueSource"})," or ",(0,n.jsx)(t.code,{children:"IDelegateSource"})," - Depending on what you're planning to write an assertion for. By extending off of the relevant interface we make sure that it won't be shown where it doesn't make sense thanks to the C# typing system."]}),"\n",(0,n.jsxs)(t.p,{children:["Your return type for the extension method should be ",(0,n.jsx)(t.code,{children:"InvokableAssertionBuilder"})]}),"\n",(0,n.jsxs)(t.p,{children:["And then finally, you just new up your custom assert condition class, and then call the extension method ",(0,n.jsx)(t.code,{children:"ChainedTo(source.AssertionBuilder, [...argumentExpression])"})," on it, which will add it to our assertion builder. You don't have to worry what that's doing behind the scenes, it's just building rules that can chain together."]}),"\n",(0,n.jsxs)(t.p,{children:["The argument expression array allows you to pass in ",(0,n.jsx)(t.code,{children:"[CallerArgumentExpression]"})," values so that your assertion errors show you the code executed to give clear exception messages."]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(t.p,{children:"Here's a fully fledged assertion in action:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-csharp",children:'public static InvokableAssertionBuilder Contains(this IValueSource valueSource, string expected, StringComparison stringComparison, [CallerArgumentExpression("expected")] string doNotPopulateThisValue1 = "", [CallerArgumentExpression("stringComparison")] string doNotPopulateThisValue2 = "")\n where TAnd : IAnd\n where TOr : IOr\n {\n return new StringContainsAssertCondition(expected, stringComparison)\n .ChainedTo(valueSource.AssertionBuilder, [doNotPopulateThisValue1, doNotPopulateThisValue2]);\n }\n'})}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-csharp",children:'public class StringContainsAssertCondition(string expected, StringComparison stringComparison)\n : AssertCondition(expected)\n{\n private protected override bool Passes(string? actualValue, Exception? exception)\n {\n if (actualValue is null)\n {\n OverriddenMessage = $"{ActualExpression ?? "Actual string"} is null";\n return false;\n }\n \n if (ExpectedValue is null)\n {\n OverriddenMessage = "No expected value given";\n return false;\n }\n \n return actualValue.Contains(ExpectedValue, stringComparison);\n }\n\n protected internal override string GetFailureMessage() => $"""\n Expected "{ActualValue}" to contain "{ExpectedValue}"\n """;\n}\n'})})]})}function u(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(d,{...e})}):d(e)}},8453:(e,t,s)=>{s.d(t,{R:()=>o,x:()=>a});var n=s(6540);const i={},r=n.createContext(i);function o(e){const t=n.useContext(r);return n.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function a(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:o(e.components),n.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.574d5de9.js b/assets/js/runtime~main.0c5b59e6.js similarity index 98% rename from assets/js/runtime~main.574d5de9.js rename to assets/js/runtime~main.0c5b59e6.js index 156a1062ef..c4c99891a3 100644 --- a/assets/js/runtime~main.574d5de9.js +++ b/assets/js/runtime~main.0c5b59e6.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,t,b,d,r={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={exports:{}};return r[e].call(t.exports,t,t.exports,f),t.exports}f.m=r,e=[],f.O=(a,t,b,d)=>{if(!t){var r=1/0;for(i=0;i=d)&&Object.keys(f.O).every((e=>f.O[e](t[o])))?t.splice(o--,1):(c=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[t,b,d]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var d=Object.create(null);f.r(d);var r={};a=a||[null,t({}),t([]),t(t)];for(var c=2&b&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,f.d(d,r),d},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({570:"91d5c99e",1114:"e322696d",1235:"a7456010",1379:"0b7a5dd9",1647:"b1a8519a",1747:"f7b7b503",2225:"4b18aed1",2321:"ba8db043",2473:"b3030475",2590:"8ff4cdb2",2748:"822bd8ab",2984:"c566dcac",3398:"8b1309c7",3604:"5c580d35",3818:"7c0d1a7d",3976:"0e384e19",4134:"393be207",4298:"13e939a4",4583:"1df93b7f",4761:"13f17bf8",4956:"e10a8de7",5742:"aba21aa0",5770:"6a12013c",5803:"f08d5324",6061:"1f391b9e",6168:"49462f00",6220:"5dbdde90",6458:"58d4c641",6532:"914d3ab3",6538:"a34b2a44",6617:"cb1d92ed",6866:"73e1c817",6969:"14eb3368",7098:"a7bd4aaa",7326:"e1f02bbc",7543:"55c176cd",7564:"2a9ef78c",7846:"be2154f8",7969:"4c5555c4",8401:"17896441",8584:"ba7c896e",8642:"9f69b8de",8715:"d3238b2f",8732:"8b247495",8887:"12f8ba17",9048:"a94703ab",9069:"3609cdcd",9081:"85aaec92",9372:"a66eab3e",9647:"5e95c892",9814:"6a21048e"}[e]||e)+"."+{570:"6039af00",1114:"f4dd2fa6",1235:"1b4d7e11",1379:"85acd131",1647:"53c91cd1",1747:"d0293669",2225:"0c56640f",2237:"c8d6c83b",2321:"bdf9e885",2473:"de698c01",2590:"1a8dddbc",2748:"fe87e631",2984:"125628dc",3398:"5dae8dc5",3604:"f2c6c9a7",3818:"6d6b04e6",3976:"c4e39ac1",4134:"732e1955",4298:"47b824e8",4583:"0ed6c3ce",4761:"5ce21056",4956:"8b2a6440",5742:"f183b5b5",5770:"5f852033",5803:"0d89f896",6061:"15657c49",6168:"fc1eaa9e",6220:"54f64f74",6458:"cde25215",6532:"29c23d13",6538:"fbd23d73",6617:"0b366f50",6866:"aecc372e",6969:"704ce381",7098:"c8828b34",7326:"dcc4b84a",7543:"e307765c",7564:"5c306a53",7846:"3ee10f1b",7969:"aa2b97b0",8401:"6598443e",8584:"3ba96841",8642:"5e8226a8",8715:"c6a41962",8732:"9e3b30b9",8887:"b11c3ad6",9048:"f6a389b6",9069:"3bafc862",9081:"7f5e34db",9372:"672ceccf",9408:"c19ac7d6",9647:"897aecb3",9814:"6affd329"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),b={},d="tunit-docs-site:",f.l=(e,a,t,r)=>{if(b[e])b[e].push(a);else{var c,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var d=b[e];if(delete b[e],c.parentNode&&c.parentNode.removeChild(c),d&&d.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),o&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/TUnit/",f.gca=function(e){return e={17896441:"8401","91d5c99e":"570",e322696d:"1114",a7456010:"1235","0b7a5dd9":"1379",b1a8519a:"1647",f7b7b503:"1747","4b18aed1":"2225",ba8db043:"2321",b3030475:"2473","8ff4cdb2":"2590","822bd8ab":"2748",c566dcac:"2984","8b1309c7":"3398","5c580d35":"3604","7c0d1a7d":"3818","0e384e19":"3976","393be207":"4134","13e939a4":"4298","1df93b7f":"4583","13f17bf8":"4761",e10a8de7:"4956",aba21aa0:"5742","6a12013c":"5770",f08d5324:"5803","1f391b9e":"6061","49462f00":"6168","5dbdde90":"6220","58d4c641":"6458","914d3ab3":"6532",a34b2a44:"6538",cb1d92ed:"6617","73e1c817":"6866","14eb3368":"6969",a7bd4aaa:"7098",e1f02bbc:"7326","55c176cd":"7543","2a9ef78c":"7564",be2154f8:"7846","4c5555c4":"7969",ba7c896e:"8584","9f69b8de":"8642",d3238b2f:"8715","8b247495":"8732","12f8ba17":"8887",a94703ab:"9048","3609cdcd":"9069","85aaec92":"9081",a66eab3e:"9372","5e95c892":"9647","6a21048e":"9814"}[e]||e,f.p+f.u(e)},(()=>{var e={5354:0,1869:0};f.f.j=(a,t)=>{var b=f.o(e,a)?e[a]:void 0;if(0!==b)if(b)t.push(b[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var d=new Promise(((t,d)=>b=e[a]=[t,d]));t.push(b[2]=d);var r=f.p+f.u(a),c=new Error;f.l(r,(t=>{if(f.o(e,a)&&(0!==(b=e[a])&&(e[a]=void 0),b)){var d=t&&("load"===t.type?"missing":t.type),r=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+d+": "+r+")",c.name="ChunkLoadError",c.type=d,c.request=r,b[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var b,d,r=t[0],c=t[1],o=t[2],n=0;if(r.some((a=>0!==e[a]))){for(b in c)f.o(c,b)&&(f.m[b]=c[b]);if(o)var i=o(f)}for(a&&a(t);n{"use strict";var e,a,t,b,d,r={},c={};function f(e){var a=c[e];if(void 0!==a)return a.exports;var t=c[e]={exports:{}};return r[e].call(t.exports,t,t.exports,f),t.exports}f.m=r,e=[],f.O=(a,t,b,d)=>{if(!t){var r=1/0;for(i=0;i=d)&&Object.keys(f.O).every((e=>f.O[e](t[o])))?t.splice(o--,1):(c=!1,d0&&e[i-1][2]>d;i--)e[i]=e[i-1];e[i]=[t,b,d]},f.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return f.d(a,{a:a}),a},t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,f.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var d=Object.create(null);f.r(d);var r={};a=a||[null,t({}),t([]),t(t)];for(var c=2&b&&e;"object"==typeof c&&!~a.indexOf(c);c=t(c))Object.getOwnPropertyNames(c).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,f.d(d,r),d},f.d=(e,a)=>{for(var t in a)f.o(a,t)&&!f.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},f.f={},f.e=e=>Promise.all(Object.keys(f.f).reduce(((a,t)=>(f.f[t](e,a),a)),[])),f.u=e=>"assets/js/"+({570:"91d5c99e",1114:"e322696d",1235:"a7456010",1379:"0b7a5dd9",1647:"b1a8519a",1747:"f7b7b503",2225:"4b18aed1",2321:"ba8db043",2473:"b3030475",2590:"8ff4cdb2",2748:"822bd8ab",2984:"c566dcac",3398:"8b1309c7",3604:"5c580d35",3818:"7c0d1a7d",3976:"0e384e19",4134:"393be207",4298:"13e939a4",4583:"1df93b7f",4761:"13f17bf8",4956:"e10a8de7",5742:"aba21aa0",5770:"6a12013c",5803:"f08d5324",6061:"1f391b9e",6168:"49462f00",6220:"5dbdde90",6458:"58d4c641",6532:"914d3ab3",6538:"a34b2a44",6617:"cb1d92ed",6866:"73e1c817",6969:"14eb3368",7098:"a7bd4aaa",7326:"e1f02bbc",7543:"55c176cd",7564:"2a9ef78c",7846:"be2154f8",7969:"4c5555c4",8401:"17896441",8584:"ba7c896e",8642:"9f69b8de",8715:"d3238b2f",8732:"8b247495",8887:"12f8ba17",9048:"a94703ab",9069:"3609cdcd",9081:"85aaec92",9372:"a66eab3e",9647:"5e95c892",9814:"6a21048e"}[e]||e)+"."+{570:"6039af00",1114:"f4dd2fa6",1235:"1b4d7e11",1379:"85acd131",1647:"53c91cd1",1747:"d0293669",2225:"0c56640f",2237:"c8d6c83b",2321:"bdf9e885",2473:"de698c01",2590:"1a8dddbc",2748:"fe87e631",2984:"125628dc",3398:"5dae8dc5",3604:"f2c6c9a7",3818:"6d6b04e6",3976:"c4e39ac1",4134:"732e1955",4298:"47b824e8",4583:"0ed6c3ce",4761:"5ce21056",4956:"8b2a6440",5742:"f183b5b5",5770:"5f852033",5803:"0d89f896",6061:"15657c49",6168:"fc1eaa9e",6220:"54f64f74",6458:"cde25215",6532:"29c23d13",6538:"fbd23d73",6617:"0b366f50",6866:"aecc372e",6969:"704ce381",7098:"c8828b34",7326:"dcc4b84a",7543:"e307765c",7564:"5c306a53",7846:"3ee10f1b",7969:"aa2b97b0",8401:"6598443e",8584:"3ba96841",8642:"5e8226a8",8715:"c6a41962",8732:"9e3b30b9",8887:"630f595c",9048:"f6a389b6",9069:"3bafc862",9081:"7f5e34db",9372:"672ceccf",9408:"c19ac7d6",9647:"897aecb3",9814:"6affd329"}[e]+".js",f.miniCssF=e=>{},f.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),f.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),b={},d="tunit-docs-site:",f.l=(e,a,t,r)=>{if(b[e])b[e].push(a);else{var c,o;if(void 0!==t)for(var n=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var d=b[e];if(delete b[e],c.parentNode&&c.parentNode.removeChild(c),d&&d.forEach((e=>e(t))),a)return a(t)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=l.bind(null,c.onerror),c.onload=l.bind(null,c.onload),o&&document.head.appendChild(c)}},f.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.p="/TUnit/",f.gca=function(e){return e={17896441:"8401","91d5c99e":"570",e322696d:"1114",a7456010:"1235","0b7a5dd9":"1379",b1a8519a:"1647",f7b7b503:"1747","4b18aed1":"2225",ba8db043:"2321",b3030475:"2473","8ff4cdb2":"2590","822bd8ab":"2748",c566dcac:"2984","8b1309c7":"3398","5c580d35":"3604","7c0d1a7d":"3818","0e384e19":"3976","393be207":"4134","13e939a4":"4298","1df93b7f":"4583","13f17bf8":"4761",e10a8de7:"4956",aba21aa0:"5742","6a12013c":"5770",f08d5324:"5803","1f391b9e":"6061","49462f00":"6168","5dbdde90":"6220","58d4c641":"6458","914d3ab3":"6532",a34b2a44:"6538",cb1d92ed:"6617","73e1c817":"6866","14eb3368":"6969",a7bd4aaa:"7098",e1f02bbc:"7326","55c176cd":"7543","2a9ef78c":"7564",be2154f8:"7846","4c5555c4":"7969",ba7c896e:"8584","9f69b8de":"8642",d3238b2f:"8715","8b247495":"8732","12f8ba17":"8887",a94703ab:"9048","3609cdcd":"9069","85aaec92":"9081",a66eab3e:"9372","5e95c892":"9647","6a21048e":"9814"}[e]||e,f.p+f.u(e)},(()=>{var e={5354:0,1869:0};f.f.j=(a,t)=>{var b=f.o(e,a)?e[a]:void 0;if(0!==b)if(b)t.push(b[2]);else if(/^(1869|5354)$/.test(a))e[a]=0;else{var d=new Promise(((t,d)=>b=e[a]=[t,d]));t.push(b[2]=d);var r=f.p+f.u(a),c=new Error;f.l(r,(t=>{if(f.o(e,a)&&(0!==(b=e[a])&&(e[a]=void 0),b)){var d=t&&("load"===t.type?"missing":t.type),r=t&&t.target&&t.target.src;c.message="Loading chunk "+a+" failed.\n("+d+": "+r+")",c.name="ChunkLoadError",c.type=d,c.request=r,b[1](c)}}),"chunk-"+a,a)}},f.O.j=a=>0===e[a];var a=(a,t)=>{var b,d,r=t[0],c=t[1],o=t[2],n=0;if(r.some((a=>0!==e[a]))){for(b in c)f.o(c,b)&&(f.m[b]=c[b]);if(o)var i=o(f)}for(a&&a(t);n Extensions | TUnit - + diff --git a/docs/category/test-framework-comparisons/index.html b/docs/category/test-framework-comparisons/index.html index dc2e9d866c..367c76553a 100644 --- a/docs/category/test-framework-comparisons/index.html +++ b/docs/category/test-framework-comparisons/index.html @@ -4,7 +4,7 @@ Test Framework Comparisons | TUnit - + diff --git a/docs/category/tutorial---assertions/index.html b/docs/category/tutorial---assertions/index.html index 42d4e25ce8..918a204d99 100644 --- a/docs/category/tutorial---assertions/index.html +++ b/docs/category/tutorial---assertions/index.html @@ -4,7 +4,7 @@ Tutorial - Assertions | TUnit - + diff --git a/docs/category/tutorial---basics/index.html b/docs/category/tutorial---basics/index.html index 1c30c86a85..5481577275 100644 --- a/docs/category/tutorial---basics/index.html +++ b/docs/category/tutorial---basics/index.html @@ -4,7 +4,7 @@ Tutorial - Basics | TUnit - + diff --git a/docs/category/tutorial---extras/index.html b/docs/category/tutorial---extras/index.html index 94ddb960d5..db2e2b420d 100644 --- a/docs/category/tutorial---extras/index.html +++ b/docs/category/tutorial---extras/index.html @@ -4,7 +4,7 @@ Tutorial - Extras | TUnit - + diff --git a/docs/comparison/attributes/index.html b/docs/comparison/attributes/index.html index c2464d3928..51755dd448 100644 --- a/docs/comparison/attributes/index.html +++ b/docs/comparison/attributes/index.html @@ -4,7 +4,7 @@ Attributes | TUnit - + diff --git a/docs/comparison/framework-differences/index.html b/docs/comparison/framework-differences/index.html index 09b4f5190f..199e5c2348 100644 --- a/docs/comparison/framework-differences/index.html +++ b/docs/comparison/framework-differences/index.html @@ -4,7 +4,7 @@ Framework Differences | TUnit - + diff --git a/docs/extensions/index.html b/docs/extensions/index.html index ba78d11c88..e4e387c0e5 100644 --- a/docs/extensions/index.html +++ b/docs/extensions/index.html @@ -4,7 +4,7 @@ Extensions | TUnit - + diff --git a/docs/intro/index.html b/docs/intro/index.html index fc549747be..18e65dd1ed 100644 --- a/docs/intro/index.html +++ b/docs/intro/index.html @@ -4,7 +4,7 @@ Intro | TUnit - + diff --git a/docs/tutorial-assertions/and-conditions/index.html b/docs/tutorial-assertions/and-conditions/index.html index 707702b663..e39f5fa1a4 100644 --- a/docs/tutorial-assertions/and-conditions/index.html +++ b/docs/tutorial-assertions/and-conditions/index.html @@ -4,7 +4,7 @@ And Conditions | TUnit - + diff --git a/docs/tutorial-assertions/awaiting/index.html b/docs/tutorial-assertions/awaiting/index.html index 688b2bde37..934a7142fb 100644 --- a/docs/tutorial-assertions/awaiting/index.html +++ b/docs/tutorial-assertions/awaiting/index.html @@ -4,7 +4,7 @@ Awaiting | TUnit - + diff --git a/docs/tutorial-assertions/congratulations/index.html b/docs/tutorial-assertions/congratulations/index.html index 7591b7dc9a..f913d628aa 100644 --- a/docs/tutorial-assertions/congratulations/index.html +++ b/docs/tutorial-assertions/congratulations/index.html @@ -4,7 +4,7 @@ Congratulations | TUnit - + diff --git a/docs/tutorial-assertions/delegates/index.html b/docs/tutorial-assertions/delegates/index.html index da3b18076e..a4b6a144ed 100644 --- a/docs/tutorial-assertions/delegates/index.html +++ b/docs/tutorial-assertions/delegates/index.html @@ -4,7 +4,7 @@ Delegates | TUnit - + diff --git a/docs/tutorial-assertions/extensibility/index.html b/docs/tutorial-assertions/extensibility/index.html index f8b65a2d5f..c9001b6646 100644 --- a/docs/tutorial-assertions/extensibility/index.html +++ b/docs/tutorial-assertions/extensibility/index.html @@ -4,7 +4,7 @@ Extensibility / Custom Assertions | TUnit - + @@ -39,7 +39,7 @@

Create the extension method! This is where things can start to look daunting because of the generic constraints, but this allows chaining assertions together.

You need to create an extension off of either IValueSource<TActual, TAnd, TOr> or IDelegateSource<TActual, TAnd, TOr> - Depending on what you're planning to write an assertion for. By extending off of the relevant interface we make sure that it won't be shown where it doesn't make sense thanks to the C# typing system.

-

Your return type for the extension method should be InvokableAssertionBuilder<string, TAnd, TOr>

+

Your return type for the extension method should be InvokableAssertionBuilder<TActual, TAnd, TOr>

And then finally, you just new up your custom assert condition class, and then call the extension method ChainedTo(source.AssertionBuilder, [...argumentExpression]) on it, which will add it to our assertion builder. You don't have to worry what that's doing behind the scenes, it's just building rules that can chain together.

The argument expression array allows you to pass in [CallerArgumentExpression] values so that your assertion errors show you the code executed to give clear exception messages.

diff --git a/docs/tutorial-assertions/or-conditions/index.html b/docs/tutorial-assertions/or-conditions/index.html index b32e8e8ea5..9d82126174 100644 --- a/docs/tutorial-assertions/or-conditions/index.html +++ b/docs/tutorial-assertions/or-conditions/index.html @@ -4,7 +4,7 @@ Or Conditions | TUnit - + diff --git a/docs/tutorial-assertions/scopes/index.html b/docs/tutorial-assertions/scopes/index.html index ce4bf977ec..739ac45630 100644 --- a/docs/tutorial-assertions/scopes/index.html +++ b/docs/tutorial-assertions/scopes/index.html @@ -4,7 +4,7 @@ Assertion Scopes | TUnit - + diff --git a/docs/tutorial-assertions/type-checking/index.html b/docs/tutorial-assertions/type-checking/index.html index 28419c9f84..8bba885ed9 100644 --- a/docs/tutorial-assertions/type-checking/index.html +++ b/docs/tutorial-assertions/type-checking/index.html @@ -4,7 +4,7 @@ Type Checking | TUnit - + diff --git a/docs/tutorial-basics/congratulations/index.html b/docs/tutorial-basics/congratulations/index.html index 51bd780c8a..af2caf7e08 100644 --- a/docs/tutorial-basics/congratulations/index.html +++ b/docs/tutorial-basics/congratulations/index.html @@ -4,7 +4,7 @@ Congratulations! | TUnit - + diff --git a/docs/tutorial-basics/data-driven-tests/index.html b/docs/tutorial-basics/data-driven-tests/index.html index ada43dae49..0eb6e60b47 100644 --- a/docs/tutorial-basics/data-driven-tests/index.html +++ b/docs/tutorial-basics/data-driven-tests/index.html @@ -4,7 +4,7 @@ Data Driven Tests | TUnit - + diff --git a/docs/tutorial-basics/data-source-driven-tests/index.html b/docs/tutorial-basics/data-source-driven-tests/index.html index 9a6acc1f9f..37ec5f5e23 100644 --- a/docs/tutorial-basics/data-source-driven-tests/index.html +++ b/docs/tutorial-basics/data-source-driven-tests/index.html @@ -4,7 +4,7 @@ Data Source Driven Tests | TUnit - + diff --git a/docs/tutorial-basics/installing/index.html b/docs/tutorial-basics/installing/index.html index a8fa29eff0..77605b4597 100644 --- a/docs/tutorial-basics/installing/index.html +++ b/docs/tutorial-basics/installing/index.html @@ -4,7 +4,7 @@ Installing TUnit | TUnit - + diff --git a/docs/tutorial-basics/matrix-tests/index.html b/docs/tutorial-basics/matrix-tests/index.html index 67f0e141d2..3627acf1e2 100644 --- a/docs/tutorial-basics/matrix-tests/index.html +++ b/docs/tutorial-basics/matrix-tests/index.html @@ -4,7 +4,7 @@ Matrix Tests | TUnit - + diff --git a/docs/tutorial-basics/running-your-tests/index.html b/docs/tutorial-basics/running-your-tests/index.html index f3791bffec..90818dd9ad 100644 --- a/docs/tutorial-basics/running-your-tests/index.html +++ b/docs/tutorial-basics/running-your-tests/index.html @@ -4,7 +4,7 @@ Running your tests | TUnit - + diff --git a/docs/tutorial-basics/things-to-know/index.html b/docs/tutorial-basics/things-to-know/index.html index fb394586fe..2c0cb65bda 100644 --- a/docs/tutorial-basics/things-to-know/index.html +++ b/docs/tutorial-basics/things-to-know/index.html @@ -4,7 +4,7 @@ Things to know | TUnit - + diff --git a/docs/tutorial-basics/writing-your-first-test/index.html b/docs/tutorial-basics/writing-your-first-test/index.html index 3d8ce29fe2..5c9c44e7e7 100644 --- a/docs/tutorial-basics/writing-your-first-test/index.html +++ b/docs/tutorial-basics/writing-your-first-test/index.html @@ -4,7 +4,7 @@ Writing your first test | TUnit - + diff --git a/docs/tutorial-extras/class-constructors/index.html b/docs/tutorial-extras/class-constructors/index.html index 9181f3085f..12a88fc2a1 100644 --- a/docs/tutorial-extras/class-constructors/index.html +++ b/docs/tutorial-extras/class-constructors/index.html @@ -4,7 +4,7 @@ Class Constructor Helpers | TUnit - + diff --git a/docs/tutorial-extras/cleanup/index.html b/docs/tutorial-extras/cleanup/index.html index 1d8567b42d..45dd0981c2 100644 --- a/docs/tutorial-extras/cleanup/index.html +++ b/docs/tutorial-extras/cleanup/index.html @@ -4,7 +4,7 @@ Test Clean Ups | TUnit - + diff --git a/docs/tutorial-extras/depends-on/index.html b/docs/tutorial-extras/depends-on/index.html index 3d2445497b..7f455b853d 100644 --- a/docs/tutorial-extras/depends-on/index.html +++ b/docs/tutorial-extras/depends-on/index.html @@ -4,7 +4,7 @@ Depends On | TUnit - + diff --git a/docs/tutorial-extras/executors/index.html b/docs/tutorial-extras/executors/index.html index 3b819ebad3..496288e60d 100644 --- a/docs/tutorial-extras/executors/index.html +++ b/docs/tutorial-extras/executors/index.html @@ -4,7 +4,7 @@ Executors | TUnit - + diff --git a/docs/tutorial-extras/explicit/index.html b/docs/tutorial-extras/explicit/index.html index cfb8432af1..35f861d3f9 100644 --- a/docs/tutorial-extras/explicit/index.html +++ b/docs/tutorial-extras/explicit/index.html @@ -4,7 +4,7 @@ Explicit | TUnit - + diff --git a/docs/tutorial-extras/not-in-parallel/index.html b/docs/tutorial-extras/not-in-parallel/index.html index dd3e252017..8cf95c6864 100644 --- a/docs/tutorial-extras/not-in-parallel/index.html +++ b/docs/tutorial-extras/not-in-parallel/index.html @@ -4,7 +4,7 @@ Not in Parallel | TUnit - + diff --git a/docs/tutorial-extras/order/index.html b/docs/tutorial-extras/order/index.html index 393d7ecdd6..368d30922b 100644 --- a/docs/tutorial-extras/order/index.html +++ b/docs/tutorial-extras/order/index.html @@ -4,7 +4,7 @@ Ordering Tests | TUnit - + diff --git a/docs/tutorial-extras/parallel-limiter/index.html b/docs/tutorial-extras/parallel-limiter/index.html index 1361aaf84d..653104ced9 100644 --- a/docs/tutorial-extras/parallel-limiter/index.html +++ b/docs/tutorial-extras/parallel-limiter/index.html @@ -4,7 +4,7 @@ Parallel Limiter | TUnit - + diff --git a/docs/tutorial-extras/properties/index.html b/docs/tutorial-extras/properties/index.html index 124d406e2f..011c716808 100644 --- a/docs/tutorial-extras/properties/index.html +++ b/docs/tutorial-extras/properties/index.html @@ -4,7 +4,7 @@ Properties | TUnit - + diff --git a/docs/tutorial-extras/repeating/index.html b/docs/tutorial-extras/repeating/index.html index 5e511cd7f7..591c342d9f 100644 --- a/docs/tutorial-extras/repeating/index.html +++ b/docs/tutorial-extras/repeating/index.html @@ -4,7 +4,7 @@ Repeating | TUnit - + diff --git a/docs/tutorial-extras/retrying/index.html b/docs/tutorial-extras/retrying/index.html index ec330266b3..c3deffb5c0 100644 --- a/docs/tutorial-extras/retrying/index.html +++ b/docs/tutorial-extras/retrying/index.html @@ -4,7 +4,7 @@ Retrying | TUnit - + diff --git a/docs/tutorial-extras/setup/index.html b/docs/tutorial-extras/setup/index.html index b555170724..687436b64a 100644 --- a/docs/tutorial-extras/setup/index.html +++ b/docs/tutorial-extras/setup/index.html @@ -4,7 +4,7 @@ Test Set Ups | TUnit - + diff --git a/docs/tutorial-extras/test-context/index.html b/docs/tutorial-extras/test-context/index.html index 10059f28ba..952969b7f4 100644 --- a/docs/tutorial-extras/test-context/index.html +++ b/docs/tutorial-extras/test-context/index.html @@ -4,7 +4,7 @@ Test Context | TUnit - + diff --git a/docs/tutorial-extras/test-filters/index.html b/docs/tutorial-extras/test-filters/index.html index 564e1711d0..972220bdbe 100644 --- a/docs/tutorial-extras/test-filters/index.html +++ b/docs/tutorial-extras/test-filters/index.html @@ -4,7 +4,7 @@ Test Filters | TUnit - + diff --git a/docs/tutorial-extras/timeouts/index.html b/docs/tutorial-extras/timeouts/index.html index 8d5c815019..0828a7c24e 100644 --- a/docs/tutorial-extras/timeouts/index.html +++ b/docs/tutorial-extras/timeouts/index.html @@ -4,7 +4,7 @@ Timeouts | TUnit - + diff --git a/index.html b/index.html index c4f4eb95a2..a3230468c5 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Hello from TUnit | TUnit - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 7b18e36f67..32dd74a86a 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -4,7 +4,7 @@ Markdown page example | TUnit - +