Move some computations for Form1040 into methods.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Jan 2021 06:23:05 +0000 (01:23 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Jan 2021 06:23:05 +0000 (01:23 -0500)
Other forms can reference the values by symbolic name rather than line
number using the new SymbolicLine. Thus when Form 1040 changes with
minor line shifts, as it does in 2020, all the dependent forms do not
need to be updated.

src/core/Line.ts
src/fed2019/Form1040.ts
src/fed2019/Form1116.ts
src/fed2019/Form6251.ts
src/fed2019/Form8960.ts
src/fed2019/Form8995.ts
src/fed2019/Schedule1.ts
src/fed2019/Schedule3.ts
src/fed2019/ScheduleA.ts
src/fed2019/ScheduleD.ts
src/fed2020/Form1040.test.ts

index 821483f1e9a4608f33e37e6edcc60920c9d2b2f9..bdd55711e1f41caf7ba4486c6a430ceb0bd02b1c 100644 (file)
@@ -77,6 +77,29 @@ export class ReferenceLine<F extends Form,
   }
 };
 
+// SymbolicLine cannot be used for lines defined on F itself. For those cases, use:
+//    new ComputedLine((tr) => this.K(tr));
+export class SymbolicLine<F extends Form & { [key in K]: ComputeFunc<ReturnType<F[K]>> },
+                          K extends keyof F>
+                              extends Line<ReturnType<F[K]>> {
+  private _form: FormClass<F>;
+  private _key: K;
+
+  constructor(form: FormClass<F>, key: K, description?: string) {
+    super(description || `Reference ${form.name}/${key}`);
+    this._form = form;
+    this._key = key;
+  }
+
+  value(tr: TaxReturn): ReturnType<F[K]> {
+    Trace.begin(this);
+    const form: F = tr.findForm(this._form);
+    const value = form[this._key](tr);
+    Trace.end();
+    return value;
+  }
+}
+
 export class InputLine<U = unknown, T extends keyof U = any> extends Line<U[T]> {
   private _input: T;
   private _fallback: U[T];
index 08299eedc7308076305c04a226c05bbccb6215cf..c9e8c0641bd07b55898e00017c4cca2e7416ab7c 100644 (file)
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: GPL-3.0-only
 
 import { Form, TaxReturn } from '../core';
-import { Line, AccumulatorLine, ComputedLine, ReferenceLine, UnsupportedLine, sumFormLines, sumLineOfForms } from '../core/Line';
+import { Line, AccumulatorLine, ComputedLine, ReferenceLine, SymbolicLine, UnsupportedLine, sumFormLines, sumLineOfForms } from '../core/Line';
 import { UnsupportedFeatureError } from '../core/Errors';
 import { clampToZero, reduceBySum, undefinedToZero } from '../core/Math';
 
@@ -34,6 +34,83 @@ export interface Form1040Input {
 export default class Form1040 extends Form<Form1040Input> {
   readonly name = '1040';
 
+  taxableInterest(tr: TaxReturn): number {
+    const value = (new AccumulatorLine(Form1099INT, '1')).value(tr) +
+                  (new AccumulatorLine(Form1099INT, '3')).value(tr);
+    return value;
+  }
+
+  qualifiedDividends(tr: TaxReturn): number {
+    return this.getValue(tr, '3a');
+  }
+
+  adjustedGrossIncome(tr: TaxReturn): number {
+    return this.getValue(tr, '7b') - this.getValue(tr, '8a');
+  }
+
+  deduction(tr: TaxReturn): number {
+    let deduction = 0;
+    const schedA = tr.findForm(ScheduleA);
+    if (schedA) {
+      deduction = schedA.getValue(tr, '17');
+      if (schedA.getValue(tr, '18')) {
+        return deduction;
+      }
+    }
+
+    return Math.max(deduction, tr.constants.standardDeduction[this.filingStatus]);
+  }
+
+  qualifiedBusinessIncomeDeduction(tr: TaxReturn): number {
+    const f8995 = tr.findForm(Form8995REIT);
+    if (f8995)
+      return f8995.getValue(tr, '39');
+    return 0;
+  }
+
+  capitalGainOrLoss(tr: TaxReturn): number {
+    const schedD = tr.findForm(ScheduleD);
+    if (!schedD)
+      return 0;
+
+    const l6 = schedD.getValue(tr, '16');
+    if (l6 >= 0)
+      return l6;
+    return schedD.getValue(tr, '21');
+  }
+
+  totalIncome(tr: TaxReturn): number {
+    return sumFormLines(tr, this, ['1', '2b', '3b', '4b', '4d', '5b', '6', '7a']);
+  }
+
+  taxableIncome(tr: TaxReturn): number {
+    return clampToZero(this.getValue(tr, '8b') - this.getValue(tr, '11a'));
+  }
+
+  tax(tr: TaxReturn): number {
+    // Not supported:
+    // Form 8814 (election to report child's interest or dividends)
+    // Form 4972 (relating to lump-sum distributions)
+
+    const schedD = tr.findForm(ScheduleD);
+    // Line 18 and 19 are not undefined or 0.
+    if (schedD && !schedD.getValue(tr, '20')) {
+      // Use ScheD tax worksheet;
+      const schedDtw = tr.findForm(ScheduleDTaxWorksheet);
+      if (schedDtw)
+        return schedDtw.getValue(tr, '47');
+    }
+
+    // If there are qualified dividends, use the QDCGTW.
+    if (this.qualifiedDividends(tr) > 0) {
+      const qdcgtw = tr.getForm(QDCGTaxWorksheet);
+      return qdcgtw.getValue(tr, '27');
+    }
+
+    // Otherwise, compute just on taxable income.
+    return computeTax(this.taxableIncome(tr), tr);
+  }
+
   readonly lines = {
     '1': new AccumulatorLine(W2, '1', 'Wages, salaries, tips, etc.'),
     '2a': new ComputedLine((tr): number => {
@@ -41,11 +118,7 @@ export default class Form1040 extends Form<Form1040Input> {
                     (new AccumulatorLine(Form1099DIV, '11')).value(tr);
       return value;
     }, 'Tax-exempt interest'),
-    '2b': new ComputedLine((tr): number => {
-      const value = (new AccumulatorLine(Form1099INT, '1')).value(tr) +
-                    (new AccumulatorLine(Form1099INT, '3')).value(tr);
-      return value;
-    }, 'Taxable interest'),
+    '2b': new ComputedLine((tr) => this.taxableInterest(tr), 'Taxable interest'),
     '3a': new AccumulatorLine(Form1099DIV, '1b', 'Qualified dividends'),
     '3b': new AccumulatorLine(Form1099DIV, '1a', 'Ordinary dividends'),
     '4a': new ComputedLine((tr): number => {
@@ -60,78 +133,25 @@ export default class Form1040 extends Form<Form1040Input> {
     '4d': new UnsupportedLine('Pensions and annuities, taxable amount'),
     '5a': new UnsupportedLine('Social security benefits'),
     '5b': new UnsupportedLine('Social security benefits, taxable amount'),
-    '6': new ComputedLine((tr): number => {
-      const schedD = tr.findForm(ScheduleD);
-      if (!schedD)
-        return 0;
-
-      const l6 = schedD.getValue(tr, '16');
-      if (l6 >= 0)
-        return l6;
-      return schedD.getValue(tr, '21');
-    }, 'Capital gain/loss'),
+    '6': new ComputedLine((tr) => this.capitalGainOrLoss(tr), 'Capital gain/loss'),
     '7a': new ReferenceLine(Schedule1, '9', 'Other income from Schedule 1', 0),
 
-    '7b': new ComputedLine((tr): number => {
-      return sumFormLines(tr, this, ['1', '2b', '3b', '4b', '4d', '5b', '6', '7a']);
-    }, 'Total income'),
+    '7b': new ComputedLine((tr) => this.totalIncome(tr), 'Total income'),
 
     '8a': new ReferenceLine(Schedule1, '22', 'Adjustments to income', 0),
 
-    '8b': new ComputedLine((tr): number => {
-      return this.getValue(tr, '7b') - this.getValue(tr, '8a');
-    }, 'Adjusted gross income'),
-
-    '9': new ComputedLine((tr): number => {
-      let deduction = 0;
-      const schedA = tr.findForm(ScheduleA);
-      if (schedA) {
-        deduction = schedA.getValue(tr, '17');
-        if (schedA.getValue(tr, '18')) {
-          return deduction;
-        }
-      }
+    '8b': new ComputedLine((tr) => this.adjustedGrossIncome(tr), 'Adjusted gross income'),
 
-      return Math.max(deduction, tr.constants.standardDeduction[this.filingStatus]);
-    }, 'Deduction'),
+    '9': new ComputedLine((tr) => this.deduction(tr), 'Deduction'),
 
-    '10': new ComputedLine((tr): number => {
-      const f8995 = tr.findForm(Form8995REIT);
-      if (f8995)
-        return f8995.getValue(tr, '39');
-      return 0;
-    }, 'Qualified business income deduction'),
+    '10': new ComputedLine((tr) => this.qualifiedBusinessIncomeDeduction(tr), 'Qualified business income deduction'),
 
     '11a': new ComputedLine((tr): number => {
       return this.getValue(tr, '9') + this.getValue(tr, '10');
     }),
-    '11b': new ComputedLine((tr): number => {
-      return clampToZero(this.getValue(tr, '8b') - this.getValue(tr, '11a'));
-    }, 'Taxable income'),
-
-    '12a': new ComputedLine((tr): number => {
-      // Not supported:
-      // Form 8814 (election to report child's interest or dividends)
-      // Form 4972 (relating to lump-sum distributions)
-
-      const schedD = tr.findForm(ScheduleD);
-      // Line 18 and 19 are not undefined or 0.
-      if (schedD && !schedD.getValue(tr, '20')) {
-        // Use ScheD tax worksheet;
-        const schedDtw = tr.findForm(ScheduleDTaxWorksheet);
-        if (schedDtw)
-          return schedDtw.getValue(tr, '47');
-      }
-
-      // If there are qualified dividends, use the QDCGTW.
-      if (this.getValue(tr, '3a') > 0) {
-        const qdcgtw = tr.getForm(QDCGTaxWorksheet);
-        return qdcgtw.getValue(tr, '27');
-      }
+    '11b': new ComputedLine((tr) => this.taxableIncome(tr), 'Taxable income'),
 
-      // Otherwise, compute just on taxable income.
-      return computeTax(this.getValue(tr, '11b'), tr);
-    }, 'Tax'),
+    '12a': new ComputedLine((tr) => this.tax(tr), 'Tax'),
 
     '12b': new ComputedLine((tr): number => {
       return this.getValue(tr, '12a') + tr.getForm(Schedule2).getValue(tr, '3');
@@ -219,13 +239,13 @@ export class QDCGTaxWorksheet extends Form {
   readonly name = 'QDCG Tax Worksheet';
 
   readonly lines = {
-    '1': new ReferenceLine(Form1040, '11b', 'Taxable income'),
+    '1': new SymbolicLine(Form1040, 'taxableIncome', 'Taxable income'),
     '2': new ReferenceLine(Form1040, '3a', 'Qualified dividends'),
     '3': new ComputedLine((tr): number => {
       const schedD = tr.findForm(ScheduleD);
       if (schedD)
         return clampToZero(Math.min(schedD.getValue(tr, '15'), schedD.getValue(tr, '16')));
-      return tr.getForm(Form1040).getValue(tr, '6');
+      return tr.getForm(Form1040).capitalGainOrLoss(tr);
     }),
     '4': new ComputedLine((tr): number => this.getValue(tr, '2') + this.getValue(tr, '3')),
     '5': new UnsupportedLine('Form 4952@4g (Investment interest expense deduction)'),
index d5dcdfd542f511ff20ebb25d6cf8c6242d42ccc7..1514b51cbf65def05807bef7bdcd9587a55068e8 100644 (file)
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: GPL-3.0-only
 
 import { Form, Person, TaxReturn } from '../core';
-import { ComputedLine, InputLine, ReferenceLine, UnsupportedLine, sumFormLines } from '../core/Line';
+import { Line, ComputedLine, InputLine, ReferenceLine, SymbolicLine, UnsupportedLine, sumFormLines } from '../core/Line';
 import { UnsupportedFeatureError } from '../core/Errors';
 import { reduceBySum } from '../core/Math';
 
@@ -48,7 +48,7 @@ export default class Form1116 extends Form<Form1116Input> {
     '1a': new Input('grossForeignIncome'),
     // 1b not supported - services as an employee.
     '2': new UnsupportedLine('Expenses definitely related to the income'),
-    '3a': new ReferenceLine(Form1040, '9', 'Deductions'),
+    '3a': new SymbolicLine(Form1040, 'deduction', 'Deductions'),
     '3b': new UnsupportedLine('Other deductions'),
     '3c': new ComputedLine((tr): number => {
       return this.getValue(tr, '3a') + this.getValue(tr, '3b');
@@ -58,7 +58,7 @@ export default class Form1116 extends Form<Form1116Input> {
       const f1040 = tr.findForm(Form1040);
       // Take total income, but do not net capital gains out with losses, so remove
       // line 6.
-      let grossIncome = f1040.getValue(tr, '7b') - f1040.getValue(tr, '6');
+      let grossIncome = f1040.totalIncome(tr) - f1040.capitalGainOrLoss(tr);
       const f8949 = tr.findForm(Form8949);
       if (f8949) {
         const keys: (keyof Form8949['lines'])[] = ['boxA', 'boxB', 'boxC', 'boxD', 'boxE', 'boxF'];
@@ -98,10 +98,10 @@ export default class Form1116 extends Form<Form1116Input> {
     '16': new UnsupportedLine('Adjustments to line 15'),
     '17': new ComputedLine((tr): number => this.getValue(tr, '15') + this.getValue(tr, '16')),
     // TODO - This does not handle necessary adjustments.
-    '18': new ReferenceLine(Form1040, '11b'),
+    '18': new SymbolicLine(Form1040, 'taxableIncome'),
     '19': new ComputedLine((tr): number => this.getValue(tr, '17') / this.getValue(tr, '18')),
     '20': new ComputedLine((tr): number => {
-      let value = tr.getForm(Form1040).getValue(tr, '12a');
+      let value = tr.getForm(Form1040).tax(tr);
       const sched2 = tr.findForm(Schedule2);
       if (sched2)
         value += sched2.getValue(tr, '2');
index 11aa7d3a6cfd87a688aca2fe14c5d1585ce22372..25e262188f4635b0267fca4b1154e2aba3065ade 100644 (file)
@@ -21,14 +21,14 @@ export default class Form6251 extends Form {
     // Part I
     '1': new ComputedLine((tr): number => {
       const f1040 = tr.getForm(Form1040);
-      const l11b = f1040.getValue(tr, '11b');
-      if (l11b > 0)
-        return l11b;
-      return f1040.getValue(tr, '8b') - f1040.getValue(tr, '9') - f1040.getValue(tr, '10');
+      const income = f1040.taxableIncome(tr);
+      if (income > 0)
+        return income;
+      return f1040.adjustedGrossIncome(tr) - f1040.deduction(tr) - f1040.qualifiedBusinessIncomeDeduction(tr);
     }),
     '2a': new ComputedLine((tr): number => {
       // Not supported: Schedule A, line 7.
-      return tr.getForm(Form1040).getValue(tr, '9');
+      return tr.getForm(Form1040).deduction(tr);
     }),
     '2b': new ReferenceLine(Schedule1, '1', 'Tax refund', 0),  // Not supported - line 8 SALT.
     '2c': new UnsupportedLine('Investment interest expense'),
@@ -82,7 +82,7 @@ export default class Form6251 extends Form {
 
       const f1040 = tr.getForm(Form1040);
 
-      let part3 = f1040.getValue(tr, '3a') > 0;
+      let part3 = f1040.qualifiedDividends(tr) > 0;
 
       const schedD = tr.findForm(ScheduleD);
       if (schedD) {
@@ -100,7 +100,7 @@ export default class Form6251 extends Form {
       return this.getValue(tr, '7') - this.getValue(tr, '8');
     }, 'Tentative minimum tax'),
     '10': new ComputedLine((tr): number => {
-      let value = tr.getForm(Form1040).getValue(tr, '12a');
+      let value = tr.getForm(Form1040).tax(tr);
       const sched2 = tr.findForm(Schedule2);
       if (sched2) {
         value += sched2.getValue(tr, '2');
index c6be3203ad2b1ae48b688208372f922dc0cae3e8..1e41acaf86635c34c6d7f2149e0a4f3ad553f8d8 100644 (file)
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: GPL-3.0-only
 
 import { Form, TaxReturn } from '../core';
-import { ComputedLine, ReferenceLine, UnsupportedLine, sumFormLines } from '../core/Line';
+import { Line, ComputedLine, ReferenceLine, SymbolicLine, UnsupportedLine, sumFormLines } from '../core/Line';
 import { clampToZero, undefinedToZero } from '../core/Math';
 
 import { Constants } from './TaxReturn';
@@ -17,14 +17,14 @@ export default class Form8960 extends Form {
   readonly lines = {
     // Part 1
     // Section 6013 elections not supported.
-    '1': new ReferenceLine(Form1040, '2b', 'Taxable interest'),
+    '1': new SymbolicLine(Form1040, 'taxableInterest', 'Taxable interest'),
     '2': new ReferenceLine(Form1040, '3b', 'Ordinary dividends'),
     '3': new UnsupportedLine('Annuities'),
     '4a': new UnsupportedLine('Rental real estate, royalties, partnerships, S corporations, trusts, etc'),
     '4b': new UnsupportedLine('Adjustment for net income or loss derived in the ordinary course of a nonsection 1411 trade or business'),
     '4c': new ComputedLine((tr): number => this.getValue(tr, '4a') + this.getValue(tr, '4b')),
     '5a': new ComputedLine((tr): number => {
-      return (new ReferenceLine(Form1040, '6')).value(tr) +
+      return (new SymbolicLine(Form1040, 'capitalGainOrLoss')).value(tr) +
              undefinedToZero(new ReferenceLine(Schedule1, '4', undefined, 0).value(tr));
     }, 'Net gain or loss'),
     '5b': new UnsupportedLine('Net gain or loss from disposition of property that is not subject to net investment income tax'),
@@ -48,7 +48,7 @@ export default class Form8960 extends Form {
 
     // Part 3
     '12': new ComputedLine((tr): number => this.getValue(tr, '8') - this.getValue(tr, '11'), 'Net investment income'),
-    '13': new ReferenceLine(Form1040, '8b', 'Modified adjusted gross income'),
+    '13': new SymbolicLine(Form1040, 'adjustedGrossIncome', 'Modified adjusted gross income'),
     '14': new ComputedLine((tr): number => {
       return Form8960.filingStatusLimit(tr);
     }, 'Threshold'),
index fbbc2d2140f7f43b0f47ea574f9830c6c747866f..9dedfc2ebd1bc29b1d2554ecd7a7ccf8491758d5 100644 (file)
@@ -32,12 +32,12 @@ export default class Form8995REIT extends Form {
     '32': new ComputedLine((tr): number => this.getValue(tr, '27') + this.getValue(tr, '31'), 'QBI deduction before limitation'),
     '33': new ComputedLine((tr): number => {
       const f1040 = tr.getForm(Form1040);
-      return f1040.getValue(tr, '8b') - f1040.getValue(tr, '9');
+      return f1040.adjustedGrossIncome(tr) - f1040.deduction(tr);
     }, 'Taxable income before deduction'),
     '34': new ComputedLine((tr): number => {
       const f1040 = tr.getForm(Form1040);
 
-      let value = f1040.getValue(tr, '3a');
+      let value = f1040.qualifiedDividends(tr);
 
       const schedD = tr.findForm(ScheduleD);
       if (schedD) {
@@ -45,7 +45,7 @@ export default class Form8995REIT extends Form {
           clampToZero(schedD.getValue(tr, '15')),
           clampToZero(schedD.getValue(tr, '16')));
       } else {
-        value += f1040.getValue(tr, '6');
+        value += f1040.capitalGainOrLoss(tr);
       }
 
       return value;
index deaa2830b1c095bc82fc55832e9eb1226dbc5b15..4f609babf711780a152488c04d6b43ed95849ad5 100644 (file)
@@ -9,7 +9,7 @@ import * as Trace from '../core/Trace';
 import { NotFoundError, UnsupportedFeatureError } from '../core/Errors';
 import { undefinedToZero } from '../core/Math';
 
-import Form1040, { FilingStatus } from './Form1040';
+import { FilingStatus } from './Form1040';
 
 export interface Schedule1Input {
   // Additional Income
index c8e01cf40818b5ed364f361b6e45a6bf8f400e41..ca4ed79fa8e95e350a762c49b0ba0fc635bff85d 100644 (file)
@@ -31,7 +31,7 @@ export default class Schedule3 extends Form<Schedule3Input> {
 
       if (totalForeignTax < limit) {
         const sched2l2 = new ReferenceLine(Schedule2, '2', undefined, 0);
-        return Math.min(totalForeignTax, f1040.getValue(tr, '12a') + sched2l2.value(tr));
+        return Math.min(totalForeignTax, f1040.tax(tr) + sched2l2.value(tr));
       }
       return tr.getForm(Form1116).getValue(tr, '33');
     }, 'Foreign tax credit'),
index af8946f38152238238a8f5e5d238774b64b7bf03..5b238ad381768ab564976253e57d74bd5181cfc7 100644 (file)
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: GPL-3.0-only
 
 import { Form } from '../core';
-import { ComputedLine, InputLine, ReferenceLine, UnsupportedLine, sumFormLines } from '../core/Line';
+import { Line, ComputedLine, InputLine, ReferenceLine, SymbolicLine, UnsupportedLine, sumFormLines } from '../core/Line';
 import { clampToZero } from '../core/Math';
 
 import Form1040, { FilingStatus } from './Form1040';
@@ -40,7 +40,7 @@ export default class ScheduleA extends Form<ScheduleAInput> {
   readonly lines = {
     // Medical and dental expenses
     '1': new Input('medicalAndDentalExpenses', 'Medical and dental expenses', 0),
-    '2': new ReferenceLine(Form1040, '8b'),
+    '2': new SymbolicLine(Form1040, 'adjustedGrossIncome'),
     '3': new ComputedLine((tr): number => this.getValue(tr, '2') * tr.constants.medicalDeductionLimitationPercent),
     '4': new ComputedLine((tr): number => clampToZero(this.getValue(tr, '1') - this.getValue(tr, '3'))),
 
index 425608bd7221cdd214fcf3fa70613d42f19580cd..40824db7ae84d70025e040f1c50df456323980e6 100644 (file)
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: GPL-3.0-only
 
 import { Form, Person, TaxReturn } from '../core';
-import { Line, AccumulatorLine, ComputedLine, ReferenceLine, UnsupportedLine, sumFormLines, sumLineOfForms } from '../core/Line';
+import { Line, AccumulatorLine, ComputedLine, ReferenceLine, SymbolicLine, UnsupportedLine, sumFormLines, sumLineOfForms } from '../core/Line';
 import { Literal, clampToZero } from '../core/Math';
 import { NotFoundError, UnsupportedFeatureError } from '../core/Errors';
 
@@ -80,7 +80,7 @@ export default class ScheduleD extends Form {
     }, 'Net capital loss'),
 
     '22': new ComputedLine((tr): boolean => {
-      return tr.getForm(Form1040).getValue(tr, '3a') > 0;
+      return tr.getForm(Form1040).qualifiedDividends(tr) > 0;
     }, 'Need QD/CG Tax Worksheet'),
   };
 };
@@ -89,8 +89,8 @@ export class ScheduleDTaxWorksheet extends Form {
   readonly name = 'Schedule D Tax Worksheet';
 
   readonly lines = {
-    '1': new ReferenceLine(Form1040, '11b', 'Taxable income'),
-    '2': new ReferenceLine(Form1040, '3a', 'Qualified dividends'),
+    '1': new SymbolicLine(Form1040, 'taxableIncome', 'Taxable income'),
+    '2': new SymbolicLine(Form1040, 'qualifiedDividends', 'Qualified dividends'),
     '3': new UnsupportedLine('Form 4952@4g'),
     '4': new UnsupportedLine('Form 4952@4e'),
     '5': new ComputedLine((tr): number => 0),
index 76f37b100fa5cd335353855852ae463b4abf1a09..dc12c6f6de371f308b8027d401a2223c8315d84f 100644 (file)
@@ -19,6 +19,7 @@ test('standard deduction', () => {
   for (const filingStatus of Object.values(FilingStatus)) {
     const tr = new TaxReturn();
     const f = new Form1040({ filingStatus });
+    tr.addForm(f);
     expect(f.getValue(tr, '9')).toBe(filingStatusToResult[filingStatus]);
   }
 });