テーブル、グループに対する循環参照エラー検知を修正、ErrorTypeの循環参照エラーのつづりを修正。
@@ -365,7 +365,7 @@ | ||
365 | 365 | c1.setValue("=c1+1"); |
366 | 366 | assertEquals(CellType.FORMULA, c1.getCellType()); |
367 | 367 | assertEquals(Element.ElementType.ERROR, c1.getValue().getType()); |
368 | - assertEquals(Element.ErrorType.CIRCULER_REFERENCE, c1.getValue().getErrorType()); | |
368 | + assertEquals(Element.ErrorType.CIRCULAR_REFERENCE, c1.getValue().getErrorType()); | |
369 | 369 | c1.setValue("=c2+1"); |
370 | 370 | assertEquals(CellType.FORMULA, c1.getCellType()); |
371 | 371 | assertEquals(Element.ElementType.NUMBER, c1.getValue().getType()); |
@@ -29,6 +29,9 @@ | ||
29 | 29 | import com.nissy_ki_chi.jpicosheet.core.ReferenceNotFoundException; |
30 | 30 | import com.nissy_ki_chi.jpicosheet.core.Sheet; |
31 | 31 | import com.nissy_ki_chi.jpicosheet.core.Table; |
32 | +import com.nissy_ki_chi.jpicosheet.core.Cell.CellStatus; | |
33 | +import com.nissy_ki_chi.jpicosheet.core.Element.ElementType; | |
34 | +import com.nissy_ki_chi.jpicosheet.core.Element.ErrorType; | |
32 | 35 | |
33 | 36 | import junit.framework.TestCase; |
34 | 37 |
@@ -671,4 +674,47 @@ | ||
671 | 674 | |
672 | 675 | } |
673 | 676 | |
677 | + | |
678 | + public void testCircularReferenceTable1() { | |
679 | + | |
680 | + Table t1 = sheet.addTable("circular1#", 2, 2); | |
681 | + t1.getCell(0, 1).setNumberValue("100"); | |
682 | + t1.getCell(1, 0).setNumberValue("200"); | |
683 | + t1.getCell(1, 1).setNumberValue("300"); | |
684 | + Table t2 = sheet.addTable("circular2#", 2, 2); | |
685 | + t2.getCell(0, 1).setNumberValue("1"); | |
686 | + t2.getCell(1, 0).setNumberValue("2"); | |
687 | + t2.getCell(1, 1).setNumberValue("3"); | |
688 | + Cell t1r0c0 = sheet.getCell("circular1#R0C0").setFormula("SUM(circular2#)"); | |
689 | + assertTrue(t1r0c0.getStatus() == CellStatus.CALCULATED); | |
690 | + | |
691 | + Cell t1r0c1 = sheet.getCell("circular1#R0C1").setFormula("SUM(circular1#)"); | |
692 | + assertTrue((t1r0c1.getStatus() == CellStatus.ERROR) && | |
693 | + (t1r0c1.getValueType() == ElementType.ERROR) && | |
694 | + (t1r0c1.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE)); | |
695 | + | |
696 | + } | |
697 | + | |
698 | + public void testCircularReferenceTable2() { | |
699 | + | |
700 | + Table t1 = sheet.addTable("circular1#", 2, 2); | |
701 | + t1.getCell(0, 1).setNumberValue("100"); | |
702 | + t1.getCell(1, 0).setNumberValue("200"); | |
703 | + t1.getCell(1, 1).setNumberValue("300"); | |
704 | + Table t2 = sheet.addTable("circular2#", 2, 2); | |
705 | + t2.getCell(0, 1).setNumberValue("1"); | |
706 | + t2.getCell(1, 0).setNumberValue("2"); | |
707 | + t2.getCell(1, 1).setNumberValue("3"); | |
708 | + Cell t1r0c0 = sheet.getCell("circular1#R0C0").setFormula("SUM(circular2#)"); | |
709 | + assertTrue(t1r0c0.getStatus() == CellStatus.CALCULATED); | |
710 | + | |
711 | + Cell t2r0c0 = sheet.getCell("circular2#R0C0").setFormula("SUM(circular1#)"); | |
712 | + assertTrue((t2r0c0.getStatus() == CellStatus.ERROR) && | |
713 | + (t2r0c0.getValueType() == ElementType.ERROR) && | |
714 | + (t2r0c0.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE)); | |
715 | + | |
716 | + assertTrue((t1r0c0.getStatus() == CellStatus.ERROR) && | |
717 | + (t1r0c0.getValueType() == ElementType.ERROR) && | |
718 | + (t1r0c0.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE)); | |
719 | + } | |
674 | 720 | } |
@@ -418,8 +418,8 @@ | ||
418 | 418 | elem = Element.newElement(ElementType.BOOLEAN, new Boolean(false)); |
419 | 419 | assertEquals("BOOLEAN:false", elem.toString()); |
420 | 420 | |
421 | - elem = Element.newElement(ElementType.ERROR, Element.ErrorType.CIRCULER_REFERENCE ); | |
422 | - assertEquals("ERROR:CIRCULER_REFERENCE", elem.toString()); | |
421 | + elem = Element.newElement(ElementType.ERROR, Element.ErrorType.CIRCULAR_REFERENCE ); | |
422 | + assertEquals("ERROR:CIRCULAR_REFERENCE", elem.toString()); | |
423 | 423 | |
424 | 424 | elem = Element.newElement(ElementType.FUNCTION, "myFunction"); |
425 | 425 | assertEquals("FUNCTION:myFunction", elem.toString()); |
@@ -138,21 +138,54 @@ | ||
138 | 138 | assertEquals(sheet.getCell("calc1").getValue().getNumber(), new BigDecimal(1+2+3+4+5+6)); |
139 | 139 | } |
140 | 140 | |
141 | -// Groups in Group はしばらく実装中止 | |
142 | -// public void testCircurationGroup() { | |
143 | -// // グループの循環参照はチェックされエラーとならなければならない。 | |
144 | -// | |
145 | -// Cell c1 = sheet.addCell("cell1").setNumberValue("123"); | |
146 | -// Group group1 = sheet.addGroup("group1@").addCell(c1); | |
147 | -// Group group2 = sheet.addGroup("group2@").addGroup(group1); | |
148 | -// | |
149 | -// group1.addGroup(group2); | |
150 | -// | |
151 | -// Cell c2 = sheet.addCell("cell2").setFormula("SUM(group2@)"); | |
152 | -// assertEquals(ElementType.ERROR, c2.getValue().getType()); | |
153 | -// assertEquals(ErrorType.CIRCULER_REFERENCE, c2.getValue().getErrorType()); | |
154 | -// } | |
155 | 141 | |
142 | + public void testCircularReferenceGroup1() { | |
143 | + | |
144 | + // グループの循環参照はチェックされエラーとならなければならない。 | |
145 | + Cell a = sheet.addCell("a").setNumberValue("100"); | |
146 | + Cell b = sheet.addCell("b").setNumberValue("200"); | |
147 | + Cell c = sheet.addCell("c").setNumberValue("300"); | |
148 | + sheet.addGroup("group1@").addCell(a).addCell(b).addCell(c); | |
149 | + | |
150 | + Cell sum1 = sheet.addCell("sum1").setFormula("SUM(group1@)"); | |
151 | + assertTrue(sum1.getStatus() == CellStatus.CALCULATED); | |
152 | + | |
153 | + // group1@に含まれるセルaに、group1@を使った式をセット | |
154 | + a.setFormula("SUM(group1@)"); | |
155 | + assertTrue((a.getStatus() == CellStatus.ERROR) && | |
156 | + (a.getValueType() == ElementType.ERROR) && | |
157 | + (a.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE) ); | |
158 | + | |
159 | + } | |
160 | + | |
161 | + public void testCircularReferenceGroup2() { | |
162 | + | |
163 | + // グループが他のグループを使った計算を行うことはOKだが、お互いを参照すると循環参照 | |
164 | + Cell a = sheet.addCell("a").setNumberValue("100"); | |
165 | + Cell b = sheet.addCell("b").setNumberValue("200"); | |
166 | + Cell c = sheet.addCell("c").setNumberValue("300"); | |
167 | + Group group1 = sheet.addGroup("group1@").addCell(a).addCell(b).addCell(c); | |
168 | + Cell x = sheet.addCell("x").setNumberValue("1"); | |
169 | + Cell y = sheet.addCell("y").setNumberValue("2"); | |
170 | + Cell z = sheet.addCell("z").setNumberValue("3"); | |
171 | + Group group2 = sheet.addGroup("group2@").addCell(x).addCell(y).addCell(z); | |
172 | + | |
173 | + Cell d = sheet.addCell("d").setFormula("SUM(group2@)"); | |
174 | + group1.addCell(d); | |
175 | + assertTrue((d.getStatus() == CellStatus.CALCULATED)); | |
176 | + | |
177 | + Cell w = sheet.addCell("w").setFormula("SUM(group1@)"); | |
178 | + group2.addCell(w); | |
179 | + // d,wともに循環参照エラー | |
180 | + assertTrue((w.getStatus() == CellStatus.ERROR) && | |
181 | + (w.getValueType() == ElementType.ERROR) && | |
182 | + (w.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE) ); | |
183 | + assertTrue((d.getStatus() == CellStatus.ERROR) && | |
184 | + (d.getValueType() == ElementType.ERROR) && | |
185 | + (d.getValue().getErrorType() == ErrorType.CIRCULAR_REFERENCE) ); | |
186 | + | |
187 | + } | |
188 | + | |
156 | 189 | public void testValueChanged() throws IllegalStateException, ReferenceNotFoundException { |
157 | 190 | // グループ中の値が変更された場合、そのグループを参照しているセルの内容は再計算されなければならない |
158 | 191 | Group group1 = sheet.addGroup("group1@") |
@@ -799,20 +799,20 @@ | ||
799 | 799 | sheet.addCell("cell1").setFormula("cell2"); |
800 | 800 | sheet.addCell("cell2").setFormula("cell3"); |
801 | 801 | sheet.addCell("cell3").setFormula("cell1"); |
802 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell1").getValueString()); | |
803 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell2").getValueString()); | |
804 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell3").getValueString()); | |
802 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell1").getValueString()); | |
803 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell2").getValueString()); | |
804 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell3").getValueString()); | |
805 | 805 | sheet.addCell("cell3").setNumberValue("11"); |
806 | 806 | assertEquals("11", sheet.getCell("cell1").getValueString()); |
807 | 807 | assertEquals("11", sheet.getCell("cell2").getValueString()); |
808 | 808 | assertEquals("11", sheet.getCell("cell3").getValueString()); |
809 | 809 | sheet.addCell("cell3").setFormula("cell1"); |
810 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell1").getValueString()); | |
811 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell2").getValueString()); | |
812 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell3").getValueString()); | |
810 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell1").getValueString()); | |
811 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell2").getValueString()); | |
812 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell3").getValueString()); | |
813 | 813 | |
814 | 814 | sheet.addCell("cell2_1").setFormula("cell2"); |
815 | - assertEquals("ERROR:CIRCULER_REFERENCE", sheet.getCell("cell2_1").getValueString()); | |
815 | + assertEquals("ERROR:CIRCULAR_REFERENCE", sheet.getCell("cell2_1").getValueString()); | |
816 | 816 | sheet.addCell("cell3").setNumberValue("11"); |
817 | 817 | assertEquals("11", sheet.getCell("cell1").getValueString()); |
818 | 818 | assertEquals("11", sheet.getCell("cell2").getValueString()); |
@@ -267,7 +267,16 @@ | ||
267 | 267 | // TODO:セル参照のたびにCollectionを得てすべてのセルの再計算チェックするのは非効率 |
268 | 268 | Collection<Cell> cells; |
269 | 269 | cells = _book.getResolver().getCellsFromGroup(token.getGroupReference()); |
270 | - recalcIfRequired(cells); | |
270 | + // 各セルに対し、必要に応じ再計算を行う | |
271 | + for (Cell groupCell: cells) { | |
272 | + recalcIfRequired(groupCell); | |
273 | + // エラーの場合、得た値をセル値としてセットし、このセルのステータスをエラーにして計算を中断する | |
274 | + if (groupCell.getValue().getType() == ElementType.ERROR) { | |
275 | + cell.setValue(groupCell.getValue()); | |
276 | + cell.setStatus(CellStatus.ERROR); | |
277 | + return; | |
278 | + } | |
279 | + } | |
271 | 280 | calcStack.push(token); |
272 | 281 | } catch (ReferenceNotFoundException e) { |
273 | 282 | // エレメントが示すグループが存在しなかった場合、このセルのステータスをエラーにして計算を中断する |
@@ -283,7 +292,16 @@ | ||
283 | 292 | // TODO:セル参照のたびにCollectionを得てすべてのセルの再計算チェックするのは非効率 |
284 | 293 | Collection<Cell> cells; |
285 | 294 | cells = _book.getResolver().getCellsFromTable(token.getTableReference()); |
286 | - recalcIfRequired(cells); | |
295 | + // 各セルに対し、必要に応じ再計算を行う | |
296 | + for (Cell groupCell: cells) { | |
297 | + recalcIfRequired(groupCell); | |
298 | + // エラーの場合、得た値をセル値としてセットし、このセルのステータスをエラーにして計算を中断する | |
299 | + if (groupCell.getValue().getType() == ElementType.ERROR) { | |
300 | + cell.setValue(groupCell.getValue()); | |
301 | + cell.setStatus(CellStatus.ERROR); | |
302 | + return; | |
303 | + } | |
304 | + } | |
287 | 305 | calcStack.push(token); |
288 | 306 | } catch (ReferenceNotFoundException e) { |
289 | 307 | // エレメントが示すテーブルが存在しなかった場合、このセルのステータスをエラーにして計算を中断する |
@@ -412,22 +430,15 @@ | ||
412 | 430 | |
413 | 431 | |
414 | 432 | /** |
415 | - * 渡されたセルのコレクションのステータスをチェックし、必要な場合再計算を行います | |
416 | - * @param cells チェックするセルのコレクション | |
433 | + * 渡されたセルのステータスが計算必要である場合、そのセルに対し計算を行います。<br> | |
434 | + * 渡されたセルのステータスが計算中であった場合、そのセルに対し循環参照エラーをセットします。 | |
435 | + * @param cell 対象とするセル | |
417 | 436 | */ |
418 | - private void recalcIfRequired(Collection<Cell> cells) { | |
419 | - | |
420 | - // 渡されたセルオブジェクトの中に計算が必要なセルがある場合、計算を行う | |
421 | - for (Cell cell: cells) { | |
422 | - recalcIfRequired(cell); | |
423 | - } | |
424 | - } | |
425 | - | |
426 | 437 | private void recalcIfRequired(Cell cell) { |
427 | 438 | // 参照するセルのステータスが計算中の場合、循環参照している |
428 | 439 | if (cell.getStatus() == CellStatus.UNDER_CALCULATION) { |
429 | 440 | // 循環参照エラーの値をセットする |
430 | - cell.setValue(Element.newElement(ElementType.ERROR, ErrorType.CIRCULER_REFERENCE)); | |
441 | + cell.setValue(Element.newElement(ElementType.ERROR, ErrorType.CIRCULAR_REFERENCE)); | |
431 | 442 | cell.setStatus(CellStatus.ERROR); |
432 | 443 | } |
433 | 444 |
@@ -123,7 +123,7 @@ | ||
123 | 123 | /** |
124 | 124 | * 循環参照 |
125 | 125 | */ |
126 | - CIRCULER_REFERENCE, | |
126 | + CIRCULAR_REFERENCE, | |
127 | 127 | |
128 | 128 | /** |
129 | 129 | * 不正なパラメータ |