When a user performs insert rows, remove rows, insert columns, or remove rows, we need to move multiple cells as a batch. The cells are moved sequentially. For each cell, its dependent alias positions are looked up and dependencies are added. However, those cells with aliases may be moved later in the batch. Thus the earlier dependencies become wrong. This commit fixes this bug by moving all the aliases before moving the cells. Unit tests are added to for this bug. fixes issue #4429
1075 lines
46 KiB
Python
1075 lines
46 KiB
Python
# (c) 2016 Werner Mayer
|
|
# (c) 2016 Eivind Kvedalen
|
|
# LGPL
|
|
|
|
import os
|
|
import sys
|
|
import math
|
|
import unittest
|
|
import FreeCAD
|
|
import Part
|
|
import Sketcher
|
|
import tempfile
|
|
from FreeCAD import Base
|
|
from FreeCAD import Units
|
|
|
|
v = Base.Vector
|
|
|
|
#----------------------------------------------------------------------------------
|
|
# define the functions to test the FreeCAD Spreadsheet module and expression engine
|
|
#----------------------------------------------------------------------------------
|
|
|
|
|
|
class SpreadsheetCases(unittest.TestCase):
|
|
def setUp(self):
|
|
self.doc = FreeCAD.newDocument()
|
|
self.TempPath = tempfile.gettempdir()
|
|
FreeCAD.Console.PrintLog( ' Using temp path: ' + self.TempPath + '\n')
|
|
|
|
def testAggregates(self):
|
|
""" Test all aggregate functions """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B13', '4')
|
|
sheet.set('B14', '5')
|
|
sheet.set('B15', '6')
|
|
sheet.set('C13', '4mm')
|
|
sheet.set('C14', '5mm')
|
|
sheet.set('C15', '6mm')
|
|
sheet.set('C16', '6')
|
|
|
|
sheet.set('A1', '=sum(1)')
|
|
sheet.set('A2', '=sum(1;2)')
|
|
sheet.set('A3', '=sum(1;2;3)')
|
|
sheet.set('A4', '=sum(1;2;3;B13)')
|
|
sheet.set('A5', '=sum(1;2;3;B13:B15)')
|
|
|
|
sheet.set('B1', '=min(1)')
|
|
sheet.set('B2', '=min(1;2)')
|
|
sheet.set('B3', '=min(1;2;3)')
|
|
sheet.set('B4', '=min(1;2;3;B13)')
|
|
sheet.set('B5', '=min(1;2;3;B13:B15)')
|
|
|
|
sheet.set('C1', '=max(1)')
|
|
sheet.set('C2', '=max(1;2)')
|
|
sheet.set('C3', '=max(1;2;3)')
|
|
sheet.set('C4', '=max(1;2;3;B13)')
|
|
sheet.set('C5', '=max(1;2;3;B13:B15)')
|
|
|
|
sheet.set('D1', '=stddev(1)')
|
|
sheet.set('D2', '=stddev(1;2)')
|
|
sheet.set('D3', '=stddev(1;2;3)')
|
|
sheet.set('D4', '=stddev(1;2;3;B13)')
|
|
sheet.set('D5', '=stddev(1;2;3;B13:B15)')
|
|
|
|
sheet.set('E1', '=count(1)')
|
|
sheet.set('E2', '=count(1;2)')
|
|
sheet.set('E3', '=count(1;2;3)')
|
|
sheet.set('E4', '=count(1;2;3;B13)')
|
|
sheet.set('E5', '=count(1;2;3;B13:B15)')
|
|
|
|
sheet.set('F1', '=average(1)')
|
|
sheet.set('F2', '=average(1;2)')
|
|
sheet.set('F3', '=average(1;2;3)')
|
|
sheet.set('F4', '=average(1;2;3;B13)')
|
|
sheet.set('F5', '=average(1;2;3;B13:B15)')
|
|
|
|
sheet.set('G1', '=average(C13:C15)')
|
|
sheet.set('G2', '=min(C13:C15)')
|
|
sheet.set('G3', '=max(C13:C15)')
|
|
sheet.set('G4', '=count(C13:C15)')
|
|
sheet.set('G5', '=stddev(C13:C15)')
|
|
sheet.set('G6', '=sum(C13:C15)')
|
|
|
|
sheet.set('H1', '=average(C13:C16)')
|
|
sheet.set('H2', '=min(C13:C16)')
|
|
sheet.set('H3', '=max(C13:C16)')
|
|
sheet.set('H4', '=count(C13:C16)')
|
|
sheet.set('H5', '=stddev(C13:C16)')
|
|
sheet.set('H6', '=sum(C13:C16)')
|
|
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A1, 1)
|
|
self.assertEqual(sheet.A2, 3)
|
|
self.assertEqual(sheet.A3, 6)
|
|
self.assertEqual(sheet.A4, 10)
|
|
self.assertEqual(sheet.A5, 21)
|
|
|
|
self.assertEqual(sheet.B1, 1)
|
|
self.assertEqual(sheet.B2, 1)
|
|
self.assertEqual(sheet.B3, 1)
|
|
self.assertEqual(sheet.B4, 1)
|
|
self.assertEqual(sheet.B5, 1)
|
|
|
|
self.assertEqual(sheet.C1, 1)
|
|
self.assertEqual(sheet.C2, 2)
|
|
self.assertEqual(sheet.C3, 3)
|
|
self.assertEqual(sheet.C4, 4)
|
|
self.assertEqual(sheet.C5, 6)
|
|
|
|
self.assertTrue(sheet.D1.startswith(u'ERR: Invalid number of entries: at least two required.'))
|
|
self.assertEqual(sheet.D2, 0.7071067811865476)
|
|
self.assertEqual(sheet.D3, 1.0)
|
|
self.assertEqual(sheet.D4, 1.2909944487358056)
|
|
self.assertEqual(sheet.D5, 1.8708286933869707)
|
|
|
|
self.assertEqual(sheet.E1, 1)
|
|
self.assertEqual(sheet.E2, 2)
|
|
self.assertEqual(sheet.E3, 3)
|
|
self.assertEqual(sheet.E4, 4)
|
|
self.assertEqual(sheet.E5, 6)
|
|
|
|
self.assertEqual(sheet.F1, 1)
|
|
self.assertEqual(sheet.F2, (1.0 + 2.0) / 2.0)
|
|
self.assertEqual(sheet.F3, (1.0 + 2 + 3) / 3)
|
|
self.assertEqual(sheet.F4, (1.0 + 2 + 3 + 4) / 4)
|
|
self.assertEqual(sheet.F5, (1.0 + 2 + 3 + 4 + 5 + 6) / 6)
|
|
|
|
self.assertEqual(sheet.G1, Units.Quantity('5 mm'))
|
|
self.assertEqual(sheet.G2, Units.Quantity('4 mm'))
|
|
self.assertEqual(sheet.G3, Units.Quantity('6 mm'))
|
|
self.assertEqual(sheet.G4, 3)
|
|
self.assertEqual(sheet.G5, Units.Quantity('1 mm'))
|
|
self.assertEqual(sheet.G6, Units.Quantity('15 mm'))
|
|
|
|
self.assertTrue(sheet.H1.startswith(u'ERR: Quantity::operator +=(): Unit mismatch in plus operation'))
|
|
self.assertTrue(sheet.H2.startswith(u'ERR: Quantity::operator <(): quantities need to have same unit to compare'))
|
|
self.assertTrue(sheet.H3.startswith(u'ERR: Quantity::operator >(): quantities need to have same unit to compare'))
|
|
self.assertEqual(sheet.H4, 4)
|
|
self.assertTrue(sheet.H5.startswith(u'ERR: Quantity::operator -(): Unit mismatch in minus operation'))
|
|
self.assertTrue(sheet.H6.startswith(u'ERR: Quantity::operator +=(): Unit mismatch in plus operation'))
|
|
|
|
def assertMostlyEqual(self, a, b):
|
|
if type(a) is Units.Quantity:
|
|
self.assertTrue( math.fabs(a.Value - b.Value) < 1e-14)
|
|
self.assertTrue( a.Unit == b.Unit)
|
|
else:
|
|
self.assertTrue( math.fabs(a - b) < 1e-14)
|
|
|
|
def testFunctions(self):
|
|
""" Test all built-in simple functions """
|
|
doc = FreeCAD.newDocument()
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '=cos(60)') # Cos
|
|
sheet.set('B1', '=cos(60deg)')
|
|
sheet.set('C1', '=cos(pi / 2 * 1rad)')
|
|
sheet.set('A2', '=sin(30)') # Sin
|
|
sheet.set('B2', '=sin(30deg)')
|
|
sheet.set('C2', '=sin(pi / 6 * 1rad)')
|
|
sheet.set('A3', '=tan(45)') # Tan
|
|
sheet.set('B3', '=tan(45deg)')
|
|
sheet.set('C3', '=tan(pi / 4 * 1rad)')
|
|
sheet.set('A4', '=abs(3)') # Abs
|
|
sheet.set('B4', '=abs(-3)')
|
|
sheet.set('C4', '=abs(-3mm)')
|
|
sheet.set('A5', '=exp(3)') # Exp
|
|
sheet.set('B5', '=exp(-3)')
|
|
sheet.set('C5', '=exp(-3mm)')
|
|
sheet.set('A6', '=log(3)') # Log
|
|
sheet.set('B6', '=log(-3)')
|
|
sheet.set('C6', '=log(-3mm)')
|
|
sheet.set('A7', '=log10(10)') # Log10
|
|
sheet.set('B7', '=log10(-3)')
|
|
sheet.set('C7', '=log10(-3mm)')
|
|
sheet.set('A8', '=round(3.4)')# Round
|
|
sheet.set('B8', '=round(3.6)')
|
|
sheet.set('C8', '=round(-3.4)')
|
|
sheet.set('D8', '=round(-3.6)')
|
|
sheet.set('E8', '=round(3.4mm)')
|
|
sheet.set('F8', '=round(3.6mm)')
|
|
sheet.set('G8', '=round(-3.4mm)')
|
|
sheet.set('H8', '=round(-3.6mm)')
|
|
sheet.set('A9', '=trunc(3.4)')# Trunc
|
|
sheet.set('B9', '=trunc(3.6)')
|
|
sheet.set('C9', '=trunc(-3.4)')
|
|
sheet.set('D9', '=trunc(-3.6)')
|
|
sheet.set('E9', '=trunc(3.4mm)')
|
|
sheet.set('F9', '=trunc(3.6mm)')
|
|
sheet.set('G9', '=trunc(-3.4mm)')
|
|
sheet.set('H9', '=trunc(-3.6mm)')
|
|
sheet.set('A10', '=ceil(3.4)') # Ceil
|
|
sheet.set('B10', '=ceil(3.6)')
|
|
sheet.set('C10', '=ceil(-3.4)')
|
|
sheet.set('D10', '=ceil(-3.6)')
|
|
sheet.set('E10', '=ceil(3.4mm)')
|
|
sheet.set('F10', '=ceil(3.6mm)')
|
|
sheet.set('G10', '=ceil(-3.4mm)')
|
|
sheet.set('H10', '=ceil(-3.6mm)')
|
|
sheet.set('A11', '=floor(3.4)')# Floor
|
|
sheet.set('B11', '=floor(3.6)')
|
|
sheet.set('C11', '=floor(-3.4)')
|
|
sheet.set('D11', '=floor(-3.6)')
|
|
sheet.set('E11', '=floor(3.4mm)')
|
|
sheet.set('F11', '=floor(3.6mm)')
|
|
sheet.set('G11', '=floor(-3.4mm)')
|
|
sheet.set('H11', '=floor(-3.6mm)')
|
|
sheet.set('A12', '=asin(0.5)') # Asin
|
|
sheet.set('B12', '=asin(0.5mm)')
|
|
sheet.set('A13', '=acos(0.5)') # Acos
|
|
sheet.set('B13', '=acos(0.5mm)')
|
|
sheet.set('A14', '=atan(sqrt(3))') # Atan
|
|
sheet.set('B14', '=atan(0.5mm)')
|
|
sheet.set('A15', '=sinh(0.5)') # Sinh
|
|
sheet.set('B15', '=sinh(0.5mm)')
|
|
sheet.set('A16', '=cosh(0.5)') # Cosh
|
|
sheet.set('B16', '=cosh(0.5mm)')
|
|
sheet.set('A17', '=tanh(0.5)') # Tanh
|
|
sheet.set('B17', '=tanh(0.5mm)')
|
|
sheet.set('A18', '=sqrt(4)') # Sqrt
|
|
sheet.set('B18', '=sqrt(4mm^2)')
|
|
sheet.set('A19', '=mod(7; 4)') # Mod
|
|
sheet.set('B19', '=mod(-7; 4)')
|
|
sheet.set('C19', '=mod(7mm; 4)')
|
|
sheet.set('D19', '=mod(7mm; 4mm)')
|
|
sheet.set('A20', '=atan2(3; 3)') # Atan2
|
|
sheet.set('B20', '=atan2(-3; 3)')
|
|
sheet.set('C20', '=atan2(3mm; 3)')
|
|
sheet.set('D20', '=atan2(3mm; 3mm)')
|
|
sheet.set('A21', '=pow(7; 4)') # Pow
|
|
sheet.set('B21', '=pow(-7; 4)')
|
|
sheet.set('C21', '=pow(7mm; 4)')
|
|
sheet.set('D21', '=pow(7mm; 4mm)')
|
|
sheet.set('A23', '=hypot(3; 4)') # Hypot
|
|
sheet.set('B23', '=hypot(-3; 4)')
|
|
sheet.set('C23', '=hypot(3mm; 4)')
|
|
sheet.set('D23', '=hypot(3mm; 4mm)')
|
|
sheet.set('A24', '=hypot(3; 4; 5)') # Hypot
|
|
sheet.set('B24', '=hypot(-3; 4; 5)')
|
|
sheet.set('C24', '=hypot(3mm; 4; 5)')
|
|
sheet.set('D24', '=hypot(3mm; 4mm; 5mm)')
|
|
sheet.set('A26', '=cath(5; 3)') # Cath
|
|
sheet.set('B26', '=cath(-5; 3)')
|
|
sheet.set('C26', '=cath(5mm; 3)')
|
|
sheet.set('D26', '=cath(5mm; 3mm)')
|
|
|
|
l = math.sqrt(5 * 5 + 4*4 + 3*3)
|
|
sheet.set('A27', '=cath(%0.15f; 5; 4)' % l) # Cath
|
|
sheet.set('B27', '=cath(%0.15f; -5; 4)' % l)
|
|
sheet.set('C27', '=cath(%0.15f mm; 5mm; 4)' % l)
|
|
sheet.set('D27', '=cath(%0.15f mm; 5mm; 4mm)' % l)
|
|
|
|
self.doc.recompute()
|
|
self.assertMostlyEqual(sheet.A1, 0.5) # Cos
|
|
self.assertMostlyEqual(sheet.B1, 0.5)
|
|
self.assertMostlyEqual(sheet.C1, 0)
|
|
self.assertMostlyEqual(sheet.A2, 0.5) # Sin
|
|
self.assertMostlyEqual(sheet.B2, 0.5)
|
|
self.assertMostlyEqual(sheet.C2, 0.5)
|
|
self.assertMostlyEqual(sheet.A3, 1) # Tan
|
|
self.assertMostlyEqual(sheet.B3, 1)
|
|
self.assertMostlyEqual(sheet.C3, 1 )
|
|
self.assertMostlyEqual(sheet.A4, 3) # Abs
|
|
self.assertMostlyEqual(sheet.B4, 3)
|
|
self.assertMostlyEqual(sheet.C4, Units.Quantity('3 mm'))
|
|
self.assertMostlyEqual(sheet.A5, math.exp(3)) # Exp
|
|
self.assertMostlyEqual(sheet.B5, math.exp(-3))
|
|
self.assertTrue(sheet.C5.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A6, math.log(3)) # Log
|
|
self.assertTrue(math.isnan(sheet.B6))
|
|
self.assertTrue(sheet.C6.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A7, math.log10(10)) # Log10
|
|
self.assertTrue(math.isnan(sheet.B7))
|
|
self.assertTrue(sheet.C7.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A8, 3) # Round
|
|
self.assertMostlyEqual(sheet.B8, 4)
|
|
self.assertMostlyEqual(sheet.C8, -3)
|
|
self.assertMostlyEqual(sheet.D8, -4)
|
|
self.assertEqual(sheet.E8, Units.Quantity('3 mm'))
|
|
self.assertEqual(sheet.F8, Units.Quantity('4 mm'))
|
|
self.assertEqual(sheet.G8, Units.Quantity('-3 mm'))
|
|
self.assertEqual(sheet.H8, Units.Quantity('-4 mm'))
|
|
self.assertMostlyEqual(sheet.A9, 3)# Trunc
|
|
self.assertMostlyEqual(sheet.B9, 3)
|
|
self.assertMostlyEqual(sheet.C9, -3)
|
|
self.assertMostlyEqual(sheet.D9, -3)
|
|
self.assertEqual(sheet.E9, Units.Quantity('3 mm'))
|
|
self.assertEqual(sheet.F9, Units.Quantity('3 mm'))
|
|
self.assertEqual(sheet.G9, Units.Quantity('-3 mm'))
|
|
self.assertEqual(sheet.H9, Units.Quantity('-3 mm'))
|
|
self.assertMostlyEqual(sheet.A10, 4) # Ceil
|
|
self.assertMostlyEqual(sheet.B10, 4)
|
|
self.assertMostlyEqual(sheet.C10, -3)
|
|
self.assertMostlyEqual(sheet.D10, -3)
|
|
self.assertMostlyEqual(sheet.E10, Units.Quantity('4 mm'))
|
|
self.assertMostlyEqual(sheet.F10, Units.Quantity('4 mm'))
|
|
self.assertMostlyEqual(sheet.G10, Units.Quantity('-3 mm'))
|
|
self.assertMostlyEqual(sheet.H10, Units.Quantity('-3 mm'))
|
|
self.assertMostlyEqual(sheet.A11, 3)# Floor
|
|
self.assertMostlyEqual(sheet.B11, 3)
|
|
self.assertMostlyEqual(sheet.C11, -4)
|
|
self.assertMostlyEqual(sheet.D11, -4)
|
|
self.assertMostlyEqual(sheet.E11, Units.Quantity('3 mm'))
|
|
self.assertMostlyEqual(sheet.F11, Units.Quantity('3 mm'))
|
|
self.assertMostlyEqual(sheet.G11, Units.Quantity('-4 mm'))
|
|
self.assertMostlyEqual(sheet.H11, Units.Quantity('-4 mm'))
|
|
self.assertMostlyEqual(sheet.A12, Units.Quantity('30 deg')) # Asin
|
|
self.assertTrue(sheet.B12.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A13, Units.Quantity('60 deg')) # Acos
|
|
self.assertTrue(sheet.B13.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A14, Units.Quantity('60 deg')) # Atan
|
|
self.assertTrue(sheet.B14.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A15, math.sinh(0.5)) # Sinh
|
|
self.assertTrue(sheet.B15.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A16, math.cosh(0.5)) # Cosh
|
|
self.assertTrue(sheet.B16.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A17, math.tanh(0.5)) # Tanh
|
|
self.assertTrue(sheet.B17.startswith(u'ERR: Unit must be empty.'))
|
|
self.assertMostlyEqual(sheet.A18, 2) # Sqrt
|
|
self.assertMostlyEqual(sheet.B18, Units.Quantity('2 mm'))
|
|
self.assertMostlyEqual(sheet.A19, 3) # Mod
|
|
self.assertMostlyEqual(sheet.B19, -3)
|
|
self.assertMostlyEqual(sheet.C19, Units.Quantity('3 mm'))
|
|
self.assertEqual(sheet.D19, 3)
|
|
self.assertMostlyEqual(sheet.A20, Units.Quantity('45 deg')) # Atan2
|
|
self.assertMostlyEqual(sheet.B20, Units.Quantity('-45 deg'))
|
|
self.assertTrue(sheet.C20.startswith(u'ERR: Units must be equal'))
|
|
self.assertMostlyEqual(sheet.D20, Units.Quantity('45 deg'))
|
|
self.assertMostlyEqual(sheet.A21, 2401) # Pow
|
|
self.assertMostlyEqual(sheet.B21, 2401)
|
|
self.assertMostlyEqual(sheet.C21, Units.Quantity('2401mm^4'))
|
|
self.assertTrue(sheet.D21.startswith(u'ERR: Exponent is not allowed to have a unit.'))
|
|
self.assertMostlyEqual(sheet.A23, 5) # Hypot
|
|
self.assertMostlyEqual(sheet.B23, 5)
|
|
self.assertTrue(sheet.C23.startswith(u'ERR: Units must be equal'))
|
|
self.assertMostlyEqual(sheet.D23, Units.Quantity('5mm'))
|
|
|
|
l = math.sqrt(3*3 + 4*4 + 5*5)
|
|
self.assertMostlyEqual(sheet.A24, l) # Hypot
|
|
self.assertMostlyEqual(sheet.B24, l)
|
|
self.assertTrue(sheet.C24.startswith(u'ERR: Units must be equal'))
|
|
self.assertMostlyEqual(sheet.D24, Units.Quantity("7.07106781186548 mm"))
|
|
self.assertMostlyEqual(sheet.A26, 4) # Cath
|
|
self.assertMostlyEqual(sheet.B26, 4)
|
|
self.assertTrue(sheet.C26.startswith(u'ERR: Units must be equal'))
|
|
self.assertMostlyEqual(sheet.D26, Units.Quantity('4mm'))
|
|
|
|
l = math.sqrt(5 * 5 + 4*4 + 3*3)
|
|
l = math.sqrt(l * l - 5*5 - 4*4)
|
|
self.assertMostlyEqual(sheet.A27, l) # Cath
|
|
self.assertMostlyEqual(sheet.B27, l)
|
|
self.assertTrue(sheet.C27.startswith(u'ERR: Units must be equal'))
|
|
self.assertMostlyEqual(sheet.D27, Units.Quantity("3 mm"))
|
|
FreeCAD.closeDocument(doc.Name)
|
|
|
|
def testRelationalOperators(self):
|
|
""" Test relational operators """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
# All should be 1 as result
|
|
sheet.set('A1', '=1 == 1 ? 1 : 0')
|
|
sheet.set('A2', '=1 != 1 ? 0 : 1')
|
|
sheet.set('A3', '=1e9 == 1e9 ? 1 : 0')
|
|
sheet.set('A4', '=1e9 != 1e9 ? 0 : 1')
|
|
sheet.set('A5', '=1 > 1 ? 0 : 1')
|
|
sheet.set('A6', '=2 > 1 ? 1 : 0')
|
|
sheet.set('A7', '=1 > 2 ? 0 : 1')
|
|
sheet.set('A8', '=1 < 1 ? 0 : 1')
|
|
sheet.set('A9', '=1 < 2 ? 1 : 0')
|
|
sheet.set('A10', '=2 < 1 ? 0 : 1')
|
|
sheet.set('A11', '=1 >= 1 ? 1 : 0')
|
|
sheet.set('A12', '=2 >= 1 ? 1 : 0')
|
|
sheet.set('A13', '=1 >= 2 ? 0 : 1')
|
|
sheet.set('A14', '=1 <= 1 ? 1 : 1')
|
|
sheet.set('A15', '=1 <= 2 ? 1 : 0')
|
|
sheet.set('A16', '=2 <= 1 ? 0 : 1')
|
|
sheet.set('A17', '=1 >= 1.000000000000001 ? 0 : 1')
|
|
sheet.set('A18', '=1 >= 1.0000000000000001 ? 1 : 0')
|
|
sheet.set('A19', '=1 <= 1.000000000000001 ? 1 : 0')
|
|
sheet.set('A20', '=1 <= 1.0000000000000001 ? 1 : 0')
|
|
sheet.set('A21', '=1 == 1.000000000000001 ? 0 : 1')
|
|
sheet.set('A22', '=1 == 1.0000000000000001 ? 1 : 0')
|
|
sheet.set('A23', '=1 != 1.000000000000001 ? 1 : 0')
|
|
sheet.set('A24', '=1 != 1.0000000000000001 ? 0 : 1')
|
|
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A1, 1)
|
|
self.assertEqual(sheet.A2, 1)
|
|
self.assertEqual(sheet.A3, 1)
|
|
self.assertEqual(sheet.A4, 1)
|
|
self.assertEqual(sheet.A5, 1)
|
|
self.assertEqual(sheet.A6, 1)
|
|
self.assertEqual(sheet.A7, 1)
|
|
self.assertEqual(sheet.A8, 1)
|
|
self.assertEqual(sheet.A9, 1)
|
|
self.assertEqual(sheet.A10, 1)
|
|
self.assertEqual(sheet.A11, 1)
|
|
self.assertEqual(sheet.A12, 1)
|
|
self.assertEqual(sheet.A13, 1)
|
|
self.assertEqual(sheet.A14, 1)
|
|
self.assertEqual(sheet.A15, 1)
|
|
self.assertEqual(sheet.A16, 1)
|
|
self.assertEqual(sheet.A17, 1)
|
|
self.assertEqual(sheet.A18, 1)
|
|
self.assertEqual(sheet.A19, 1)
|
|
self.assertEqual(sheet.A20, 1)
|
|
self.assertEqual(sheet.A21, 1)
|
|
self.assertEqual(sheet.A22, 1)
|
|
self.assertEqual(sheet.A23, 1)
|
|
self.assertEqual(sheet.A24, 1)
|
|
|
|
def testUnits(self):
|
|
""" Units -- test unit calculations. """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '=2mm + 3mm')
|
|
sheet.set('A2', '=2mm - 3mm')
|
|
sheet.set('A3', '=2mm * 3mm')
|
|
sheet.set('A4', '=4mm / 2mm')
|
|
sheet.set('A5', '=(4mm)^2')
|
|
sheet.set('A6', '=5(mm^2)')
|
|
sheet.set('A7', '=5mm^2') # ^2 operates on whole number
|
|
sheet.set('A8', '=5')
|
|
sheet.set('A9', '=5*1/K') # Currently fails
|
|
sheet.set('A10', '=5 K^-1') # Currently fails
|
|
sheet.set('A11', '=9.8 m/s^2') # Currently fails
|
|
sheet.setDisplayUnit('A8', '1/K')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A1, Units.Quantity('5mm'))
|
|
self.assertEqual(sheet.A2, Units.Quantity('-1 mm'))
|
|
self.assertEqual(sheet.A3, Units.Quantity('6 mm^2'))
|
|
self.assertEqual(sheet.A4, Units.Quantity('2'))
|
|
self.assertEqual(sheet.A5, Units.Quantity('16 mm^2'))
|
|
self.assertEqual(sheet.A6, Units.Quantity('5 mm^2'))
|
|
self.assertEqual(sheet.A7, Units.Quantity('5 mm^2'))
|
|
self.assertEqual(sheet.A8, Units.Quantity('5'))
|
|
self.assertEqual(sheet.A9, Units.Quantity('5 K^-1'))
|
|
self.assertEqual(sheet.A10, Units.Quantity('5 K^-1'))
|
|
self.assertEqual(sheet.A11, Units.Quantity('9.8 m/s^2'))
|
|
|
|
def testPrecedence(self):
|
|
""" Precedence -- test precedence for relational operators and conditional operator. """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '=1 < 2 ? 3 : 4')
|
|
sheet.set('A2', '=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8')
|
|
sheet.set('A3', '=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3')
|
|
sheet.set('A4', '=123')
|
|
sheet.set('A5', '=123 + 321')
|
|
sheet.set('A6', '=123 * 2 + 321')
|
|
sheet.set('A7', '=123 * 2 + 333 / 3')
|
|
sheet.set('A8', '=123 * (2 + 321)')
|
|
sheet.set('A9', '=3 ^ 4')
|
|
sheet.set('A10', '=3 ^ 4 * 2')
|
|
sheet.set('A11', '=3 ^ (4 * 2)')
|
|
sheet.set('A12', '=3 ^ 4 + 4')
|
|
sheet.set('A13', '=1 + 4 / 2 + 5')
|
|
sheet.set('A14', '=(3 + 6) / (1 + 2)')
|
|
sheet.set('A15', '=1 * 2 / 3 * 4')
|
|
sheet.set('A16', '=(1 * 2) / (3 * 4)')
|
|
# Test associativity
|
|
sheet.set('A17', '=3 ^ 4 ^ 2') # exponentiation is left-associative; to follow excel, openoffice, matlab, octave
|
|
sheet.set('A18', '=3 ^ (4 ^ 2)') # exponentiation is left-associative
|
|
sheet.set('A19', '=(3 ^ 4) ^ 2') # exponentiation is left-associative
|
|
sheet.set('A20', '=3 + 4 + 2')
|
|
sheet.set('A21', '=3 + (4 + 2)')
|
|
sheet.set('A22', '=(3 + 4) + 2')
|
|
sheet.set('A23', '=3 - 4 - 2')
|
|
sheet.set('A24', '=3 - (4 - 2)')
|
|
sheet.set('A25', '=(3 - 4) - 2')
|
|
sheet.set('A26', '=3 * 4 * 2')
|
|
sheet.set('A27', '=3 * (4 * 2)')
|
|
sheet.set('A28', '=(3 * 4) * 2')
|
|
sheet.set('A29', '=3 / 4 / 2')
|
|
sheet.set('A30', '=3 / (4 / 2)')
|
|
sheet.set('A31', '=(3 / 4) / 2')
|
|
sheet.set('A32', '=pi * 3')
|
|
sheet.set('A33', '=A32 / 3')
|
|
sheet.set('A34', '=1 < 2 ? <<A>> : <<B>>')
|
|
sheet.set('A35', '=min(A32:A33)')
|
|
sheet.set('A36', '=(1 < 2 ? 0 : 1) * 3')
|
|
sheet.set('A37', '=8/(2^2*2)')
|
|
sheet.set('A38', '=(2^2*2)/8')
|
|
sheet.set('A39', '=2^(2*2)/8')
|
|
sheet.set('A40', '=8/2^(2*2)')
|
|
sheet.set('A41', '=-1')
|
|
sheet.set('A42', '=-(1)')
|
|
sheet.set('A43', '=-(1 + 1)')
|
|
sheet.set('A44', '=-(1 - 1)')
|
|
sheet.set('A45', '=-(-1 + 1)')
|
|
sheet.set('A46', '=-(-1 + -1)')
|
|
sheet.set('A47', '=+1')
|
|
sheet.set('A48', '=+(1)')
|
|
sheet.set('A49', '=+(1 + 1)')
|
|
sheet.set('A50', '=+(1 - 1)')
|
|
sheet.set('A51', '=+(-1 + 1)')
|
|
sheet.set('A52', '=+(-1 + -1)')
|
|
|
|
self.doc.addObject("Part::Cylinder", "Cylinder")
|
|
# We cannot use Thickness, as this feature requires a source shape,
|
|
# otherwise it will cause recomputation failure. The new logic of
|
|
# App::Document will not continue recompute any dependent objects
|
|
|
|
# self.doc.addObject("Part::Thickness", "Pipe")
|
|
self.doc.addObject("Part::Box", "Box")
|
|
self.doc.Box.Length = 1
|
|
|
|
sheet.set('B1', '101')
|
|
sheet.set('A53', '=-(-(B1-1)/2)')
|
|
sheet.set('A54', '=-(Cylinder.Radius + Box.Length - 1"/2)')
|
|
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.getContents("A1"), "=1 < 2 ? 3 : 4")
|
|
self.assertEqual(sheet.getContents("A2"), "=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8")
|
|
self.assertEqual(sheet.getContents("A3"), "=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3")
|
|
self.assertEqual(sheet.A1, 3)
|
|
self.assertEqual(sheet.A2, 11)
|
|
self.assertEqual(sheet.A3, 44)
|
|
self.assertEqual(sheet.A4, 123)
|
|
self.assertEqual(sheet.A5, 444)
|
|
self.assertEqual(sheet.A6, 567)
|
|
self.assertEqual(sheet.A7, 357)
|
|
self.assertEqual(sheet.A8, 39729)
|
|
self.assertEqual(sheet.A9, 81)
|
|
self.assertEqual(sheet.A10, 162)
|
|
self.assertEqual(sheet.A11, 6561)
|
|
self.assertEqual(sheet.A12, 85)
|
|
self.assertEqual(sheet.A13, 8)
|
|
self.assertEqual(sheet.A14, 3)
|
|
self.assertEqual(sheet.A15, 8.0/3)
|
|
self.assertEqual(sheet.A16, 1.0/6)
|
|
self.assertEqual(sheet.A17, 6561)
|
|
self.assertEqual(sheet.A18, 43046721)
|
|
self.assertEqual(sheet.A19, 6561)
|
|
self.assertEqual(sheet.A20, 9)
|
|
self.assertEqual(sheet.A21, 9)
|
|
self.assertEqual(sheet.A22, 9)
|
|
self.assertEqual(sheet.A23, -3)
|
|
self.assertEqual(sheet.A24, 1)
|
|
self.assertEqual(sheet.A25, -3)
|
|
self.assertEqual(sheet.A26, 24)
|
|
self.assertEqual(sheet.A27, 24)
|
|
self.assertEqual(sheet.A28, 24)
|
|
self.assertEqual(sheet.A29, 3.0/8)
|
|
self.assertEqual(sheet.A30, 3.0/2)
|
|
self.assertEqual(sheet.A31, 3.0/8)
|
|
self.assertEqual(sheet.A37, 1)
|
|
self.assertEqual(sheet.A38, 1)
|
|
self.assertEqual(sheet.A39, 2)
|
|
self.assertEqual(sheet.A40, 0.5)
|
|
self.assertEqual(sheet.A41, -1)
|
|
self.assertEqual(sheet.A42, -1)
|
|
self.assertEqual(sheet.A43, -2)
|
|
self.assertEqual(sheet.A44, 0)
|
|
self.assertEqual(sheet.A45, 0)
|
|
self.assertEqual(sheet.A46, 2)
|
|
self.assertEqual(sheet.A47, 1)
|
|
self.assertEqual(sheet.A48, 1)
|
|
self.assertEqual(sheet.A49, 2)
|
|
self.assertEqual(sheet.A50, 0)
|
|
self.assertEqual(sheet.A51, 0)
|
|
self.assertEqual(sheet.A52, -2)
|
|
self.assertEqual(sheet.A53, 50)
|
|
self.assertEqual(sheet.A54, Units.Quantity('9.7mm'))
|
|
self.assertEqual(sheet.getContents('A1'), '=1 < 2 ? 3 : 4')
|
|
self.assertEqual(sheet.getContents('A2'), '=1 + 2 < 3 + 4 ? 5 + 6 : 7 + 8')
|
|
self.assertEqual(sheet.getContents('A3'), '=1 + 2 * 1 < 3 + 4 ? 5 * 2 + 6 * 3 + 2 ^ 4 : 7 * 2 + 8 * 3 + 2 ^ 3')
|
|
self.assertEqual(sheet.getContents('A4'), '123')
|
|
self.assertEqual(sheet.getContents('A5'), '=123 + 321')
|
|
self.assertEqual(sheet.getContents('A6'), '=123 * 2 + 321')
|
|
self.assertEqual(sheet.getContents('A7'), '=123 * 2 + 333 / 3')
|
|
self.assertEqual(sheet.getContents('A8'), '=123 * (2 + 321)')
|
|
self.assertEqual(sheet.getContents('A9'), '=3 ^ 4')
|
|
self.assertEqual(sheet.getContents('A10'), '=3 ^ 4 * 2')
|
|
self.assertEqual(sheet.getContents('A11'), '=3 ^ (4 * 2)')
|
|
self.assertEqual(sheet.getContents('A12'), '=3 ^ 4 + 4')
|
|
self.assertEqual(sheet.getContents('A13'), '=1 + 4 / 2 + 5')
|
|
self.assertEqual(sheet.getContents('A14'), '=(3 + 6) / (1 + 2)')
|
|
self.assertEqual(sheet.getContents('A15'), '=1 * 2 / 3 * 4')
|
|
self.assertEqual(sheet.getContents('A16'), '=1 * 2 / (3 * 4)')
|
|
self.assertEqual(sheet.getContents('A17'), '=3 ^ 4 ^ 2')
|
|
self.assertEqual(sheet.getContents('A18'), '=3 ^ (4 ^ 2)')
|
|
self.assertEqual(sheet.getContents('A19'), '=3 ^ 4 ^ 2')
|
|
self.assertEqual(sheet.getContents('A20'), '=3 + 4 + 2')
|
|
self.assertEqual(sheet.getContents('A21'), '=3 + 4 + 2')
|
|
self.assertEqual(sheet.getContents('A22'), '=3 + 4 + 2')
|
|
self.assertEqual(sheet.getContents('A23'), '=3 - 4 - 2')
|
|
self.assertEqual(sheet.getContents('A24'), '=3 - (4 - 2)')
|
|
self.assertEqual(sheet.getContents('A25'), '=3 - 4 - 2')
|
|
self.assertEqual(sheet.getContents('A26'), '=3 * 4 * 2')
|
|
self.assertEqual(sheet.getContents('A27'), '=3 * 4 * 2')
|
|
self.assertEqual(sheet.getContents('A28'), '=3 * 4 * 2')
|
|
self.assertEqual(sheet.getContents('A29'), '=3 / 4 / 2')
|
|
self.assertEqual(sheet.getContents('A30'), '=3 / (4 / 2)')
|
|
self.assertEqual(sheet.getContents('A31'), '=3 / 4 / 2')
|
|
self.assertEqual(sheet.getContents('A32'), '=pi * 3')
|
|
self.assertEqual(sheet.getContents('A33'), '=A32 / 3')
|
|
self.assertEqual(sheet.getContents('A34'), '=1 < 2 ? <<A>> : <<B>>')
|
|
self.assertEqual(sheet.getContents('A35'), '=min(A32:A33)')
|
|
self.assertEqual(sheet.getContents('A36'), '=(1 < 2 ? 0 : 1) * 3')
|
|
self.assertEqual(sheet.getContents('A37'), '=8 / (2 ^ 2 * 2)')
|
|
self.assertEqual(sheet.getContents('A38'), '=2 ^ 2 * 2 / 8')
|
|
self.assertEqual(sheet.getContents('A39'), '=2 ^ (2 * 2) / 8')
|
|
self.assertEqual(sheet.getContents('A40'), '=8 / 2 ^ (2 * 2)')
|
|
self.assertEqual(sheet.getContents('A41'), '=-1')
|
|
self.assertEqual(sheet.getContents('A42'), '=-1')
|
|
self.assertEqual(sheet.getContents('A43'), '=-(1 + 1)')
|
|
self.assertEqual(sheet.getContents('A44'), '=-(1 - 1)')
|
|
self.assertEqual(sheet.getContents('A45'), '=-(-1 + 1)')
|
|
self.assertEqual(sheet.getContents('A46'), '=-(-1 + -1)')
|
|
self.assertEqual(sheet.getContents('A47'), '=+1')
|
|
self.assertEqual(sheet.getContents('A48'), '=+1')
|
|
self.assertEqual(sheet.getContents('A49'), '=+(1 + 1)')
|
|
self.assertEqual(sheet.getContents('A50'), '=+(1 - 1)')
|
|
self.assertEqual(sheet.getContents('A51'), '=+(-1 + 1)')
|
|
self.assertEqual(sheet.getContents('A52'), '=+(-1 + -1)')
|
|
|
|
def testNumbers(self):
|
|
""" Test different numbers """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '1')
|
|
sheet.set('A2', '1.5')
|
|
sheet.set('A3', '.5')
|
|
sheet.set('A4', '1e2')
|
|
sheet.set('A5', '1E2')
|
|
sheet.set('A6', '1e-2')
|
|
sheet.set('A7', '1E-2')
|
|
sheet.set('A8', '1.5e2')
|
|
sheet.set('A9', '1.5E2')
|
|
sheet.set('A10', '1.5e-2')
|
|
sheet.set('A11', '1.5E-2')
|
|
sheet.set('A12', '.5e2')
|
|
sheet.set('A13', '.5E2')
|
|
sheet.set('A14', '.5e-2')
|
|
sheet.set('A15', '.5E-2')
|
|
sheet.set('A16', '1/1')
|
|
sheet.set('A17', '1/2')
|
|
sheet.set('A18', '2/4')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A1, 1)
|
|
self.assertEqual(sheet.A2, 1.5)
|
|
self.assertEqual(sheet.A3, 0.5)
|
|
self.assertEqual(sheet.A4, 1e2)
|
|
self.assertEqual(sheet.A5, 1e2)
|
|
self.assertEqual(sheet.A6, 1e-2)
|
|
self.assertEqual(sheet.A7, 1e-2)
|
|
self.assertEqual(sheet.A8, 1.5e2)
|
|
self.assertEqual(sheet.A9, 1.5e2)
|
|
self.assertEqual(sheet.A10, 1.5e-2)
|
|
self.assertEqual(sheet.A11, 1.5e-2)
|
|
self.assertEqual(sheet.A12, 0.5e2)
|
|
self.assertEqual(sheet.A13, 0.5e2)
|
|
self.assertEqual(sheet.A14, 0.5e-2)
|
|
self.assertEqual(sheet.A15, 0.5e-2)
|
|
self.assertEqual(sheet.A16, 1)
|
|
self.assertEqual(sheet.A17, 0.5)
|
|
self.assertEqual(sheet.A18, 0.5)
|
|
|
|
def testRemoveRows(self):
|
|
""" Removing rows -- check renaming of internal cells """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A3', '123')
|
|
sheet.set('A1', '=A3')
|
|
sheet.removeRows('2', 1)
|
|
self.assertEqual(sheet.getContents("A1"),"=A2")
|
|
|
|
def testInsertRows(self):
|
|
""" Inserting rows -- check renaming of internal cells """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B1', '=B2')
|
|
sheet.set('B2', '124')
|
|
# Calling getContents() here activates ObjectIdentifier internal cache,
|
|
# which needs to be tested as well.
|
|
self.assertEqual(sheet.getContents("B1"),"=B2")
|
|
sheet.insertRows('2', 1)
|
|
self.assertEqual(sheet.getContents("B1"),"=B3")
|
|
|
|
def testIssue3225(self):
|
|
""" Inserting rows -- check renaming of internal cells """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B2', '25')
|
|
sheet.set('B3', '=B2')
|
|
sheet.insertRows('2', 1)
|
|
self.assertEqual(sheet.getContents("B4"),"=B3")
|
|
|
|
def testRenameAlias(self):
|
|
""" Test renaming of alias1 to alias2 in a spreadsheet """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B1', '124')
|
|
sheet.setAlias('B1', 'alias1')
|
|
sheet.set('B2', '=alias1')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.get("alias1"), 124)
|
|
self.assertEqual(sheet.get("B1"), 124)
|
|
self.assertEqual(sheet.get("B2"), 124)
|
|
sheet.setAlias('B1', 'alias2')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.get("alias2"), 124)
|
|
self.assertEqual(sheet.getContents("B2"),"=alias2")
|
|
|
|
def testRenameAlias2(self):
|
|
""" Test renaming of alias1 to alias2 in a spreadsheet, when referenced from another object """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B1', '124')
|
|
sheet.setAlias('B1', 'alias1')
|
|
box = self.doc.addObject('Part::Box', 'Box')
|
|
box.setExpression('Length', 'Spreadsheet.alias1')
|
|
sheet.setAlias('B1', 'alias2')
|
|
self.assertEqual(box.ExpressionEngine[0][1], "Spreadsheet.alias2");
|
|
|
|
def testRenameAlias3(self):
|
|
""" Test renaming of document object referenced from another object """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('B1', '124')
|
|
sheet.setAlias('B1', 'alias1')
|
|
box = self.doc.addObject('Part::Box', 'Box')
|
|
box.setExpression('Length', 'Spreadsheet.alias1')
|
|
box2 = self.doc.addObject('Part::Box', 'Box')
|
|
box2.setExpression('Length', '<<Spreadsheet>>.alias1')
|
|
sheet.Label = "Params"
|
|
self.assertEqual(box.ExpressionEngine[0][1], "Spreadsheet.alias1");
|
|
self.assertEqual(box2.ExpressionEngine[0][1], "<<Params>>.alias1");
|
|
|
|
def testAlias(self):
|
|
""" Playing with aliases """
|
|
sheet = self.doc.addObject("Spreadsheet::Sheet","Calc")
|
|
sheet.setAlias("A1","Test")
|
|
self.assertEqual(sheet.getAlias("A1"),"Test")
|
|
|
|
sheet.set("A1","4711")
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.get("Test"),4711)
|
|
self.assertEqual(sheet.get("Test"),sheet.get("A1"))
|
|
|
|
def testAmbiguousAlias(self):
|
|
""" Try to set the same alias twice (bug #2402) """
|
|
sheet = self.doc.addObject("Spreadsheet::Sheet","Calc")
|
|
sheet.setAlias("A1","Test")
|
|
try:
|
|
sheet.setAlias("A2","Test")
|
|
self.fail("An ambiguous alias was set which shouldn't be allowed")
|
|
except:
|
|
self.assertEqual(sheet.getAlias("A2"),None)
|
|
|
|
def testClearAlias(self):
|
|
""" This was causing a crash """
|
|
sheet = self.doc.addObject("Spreadsheet::Sheet","Calc")
|
|
sheet.setAlias("A1","Test")
|
|
sheet.setAlias("A1","")
|
|
self.assertEqual(sheet.getAlias("A1"),None)
|
|
|
|
def testSetInvalidAlias(self):
|
|
""" Try to use a cell address as alias name """
|
|
sheet = self.doc.addObject("Spreadsheet::Sheet","Calc")
|
|
try:
|
|
sheet.setAlias("A1","B1")
|
|
except:
|
|
self.assertEqual(sheet.getAlias("A1"),None)
|
|
else:
|
|
self.fail("A cell address was used as alias which shouldn't be allowed")
|
|
|
|
def testSetInvalidAlias2(self):
|
|
""" Try to use a unit (reserved word) as alias name """
|
|
sheet = self.doc.addObject("Spreadsheet::Sheet","Calc")
|
|
try:
|
|
sheet.setAlias("A1","mA")
|
|
except:
|
|
self.assertEqual(sheet.getAlias("A1"), None)
|
|
else:
|
|
self.fail("A unit (reserved word) was used as alias which shouldn't be allowed")
|
|
|
|
def testPlacementName(self):
|
|
""" Object name is equal to property name (bug #2389) """
|
|
if not FreeCAD.GuiUp:
|
|
return
|
|
|
|
import FreeCADGui
|
|
o = self.doc.addObject("Part::FeaturePython","Placement")
|
|
FreeCADGui.Selection.addSelection(o)
|
|
|
|
def testInvoluteGear(self):
|
|
""" Support of boolean or integer values """
|
|
try:
|
|
import InvoluteGearFeature
|
|
except ImportError:
|
|
return
|
|
InvoluteGearFeature.makeInvoluteGear('InvoluteGear')
|
|
self.doc.recompute()
|
|
sketch=self.doc.addObject('Sketcher::SketchObject','Sketch')
|
|
sketch.addGeometry(Part.LineSegment(v(0,0,0),v(10,10,0)),False)
|
|
sketch.addConstraint(Sketcher.Constraint('Distance',0,65.285388))
|
|
sketch.setExpression('Constraints[0]', 'InvoluteGear.NumberOfTeeth')
|
|
self.doc.recompute()
|
|
self.assertIn('Up-to-date',sketch.State)
|
|
|
|
def testSketcher(self):
|
|
""" Mixup of Label and Name (bug #2407)"""
|
|
sketch=self.doc.addObject('Sketcher::SketchObject','Sketch')
|
|
sheet=self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.setAlias('A1', 'Length')
|
|
self.doc.recompute()
|
|
sheet.set('A1', '47,11')
|
|
self.doc.recompute()
|
|
|
|
index=sketch.addGeometry(Part.LineSegment(v(0,0,0),v(10,10,0)),False)
|
|
sketch.addConstraint(Sketcher.Constraint('Distance',index,14.0))
|
|
self.doc.recompute()
|
|
sketch.setExpression('Constraints[0]', u'<<Spreadsheet>>.Length')
|
|
self.doc.recompute()
|
|
sheet.Label="Calc"
|
|
self.doc.recompute()
|
|
self.assertEqual(sketch.ExpressionEngine[0][1],'<<Calc>>.Length')
|
|
self.assertIn('Up-to-date',sketch.State)
|
|
|
|
def testCrossDocumentLinks(self):
|
|
""" Expressions across files are not saved (bug #2442) """
|
|
|
|
# Create a box
|
|
box = self.doc.addObject('Part::Box', 'Box')
|
|
|
|
# Create a second document with a cylinder
|
|
doc2 = FreeCAD.newDocument()
|
|
cylinder = doc2.addObject('Part::Cylinder', 'Cylinder')
|
|
cylinder.setExpression('Radius', 'cube#Cube.Height')
|
|
|
|
# Save and close first document
|
|
self.doc.saveAs(self.TempPath + os.sep + 'cube.fcstd')
|
|
FreeCAD.closeDocument(self.doc.Name)
|
|
|
|
# Save and close second document
|
|
doc2.saveAs(self.TempPath + os.sep + 'cylinder.fcstd')
|
|
FreeCAD.closeDocument(doc2.Name)
|
|
|
|
# Open both documents again
|
|
self.doc = FreeCAD.openDocument(self.TempPath + os.sep + 'cube.fcstd')
|
|
doc2 = FreeCAD.openDocument(self.TempPath + os.sep + 'cylinder.fcstd')
|
|
|
|
# Check reference between them
|
|
self.assertEqual(doc2.getObject('Cylinder').ExpressionEngine[0][1], 'cube#Cube.Height')
|
|
|
|
# Close second document
|
|
FreeCAD.closeDocument(doc2.Name)
|
|
|
|
def testMatrix(self):
|
|
''' Test Matrix/Vector/Placement/Rotation operations'''
|
|
|
|
def plm_equal(plm1, plm2):
|
|
from math import sqrt
|
|
qpair = zip(plm1.Rotation.Q, plm2.Rotation.Q)
|
|
qdiff1 = sqrt(sum([(v1 - v2)**2 for v1,v2 in qpair]))
|
|
qdiff2 = sqrt(sum([(v1 + v2)**2 for v1,v2 in qpair]))
|
|
return (plm1.Base-plm2.Base).Length < 1e-7 and (qdiff1 < 1e-12 or dqiff2 < 1e-12)
|
|
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
|
|
mat = FreeCAD.Matrix()
|
|
mat.scale(2,1,2)
|
|
imat = mat.inverse()
|
|
|
|
vec = FreeCAD.Vector(2,1,2)
|
|
|
|
rot = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),45)
|
|
irot = rot.inverted()
|
|
|
|
pla = FreeCAD.Placement(vec,rot)
|
|
ipla = pla.inverse()
|
|
|
|
sheet.set('A1', '=create(<<vector>>, 2, 1, 2)')
|
|
|
|
# different ways of calling mscale()
|
|
sheet.set('B1', '=mscale(create(<<matrix>>), A1)')
|
|
sheet.set('C1', '=mscale(create(<<matrix>>), tuple(2, 1, 2))')
|
|
sheet.set('A2', '=mscale(create(<<matrix>>), 2, 1, 2)')
|
|
|
|
# test matrix power operation
|
|
sheet.set('B2', '=A2^-2')
|
|
sheet.set('C2', '=A2^-1')
|
|
sheet.set('D2', '=A2^0')
|
|
sheet.set('E2', '=A2^1')
|
|
sheet.set('F2', '=A2^2')
|
|
sheet.set('G2', '=create(<<matrix>>, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)')
|
|
sheet.set('H2', '=G2^-1')
|
|
|
|
sheet.set('A3', '=create(<<rotation>>, create(<<vector>>, 0, 1, 0), 45)')
|
|
|
|
# test rotation power operation
|
|
sheet.set('B3', '=A3^-2')
|
|
sheet.set('C3', '=A3^-1')
|
|
sheet.set('D3', '=A3^0')
|
|
sheet.set('E3', '=A3^1')
|
|
sheet.set('F3', '=A3^2')
|
|
|
|
sheet.set('A4', '=create(<<placement>>, A1, A3)')
|
|
|
|
# test placement power operation
|
|
sheet.set('B4', '=A4^-2')
|
|
sheet.set('C4', '=A4^-1')
|
|
sheet.set('D4', '=A4^0')
|
|
sheet.set('E4', '=A4^1')
|
|
sheet.set('F4', '=A4^2')
|
|
|
|
# vector transformation with mixing matrix and placement and rotation
|
|
sheet.set('A5', '=A2*A3*A4*A1')
|
|
sheet.set('B5', '=B2*B4*B3*A1')
|
|
sheet.set('C5', '=C3*C2*C4*A1')
|
|
sheet.set('D5', '=D3*D4*D2*A1')
|
|
sheet.set('E5', '=E4*E2*E3*A1')
|
|
sheet.set('F5', '=F3*F4*F2*A1')
|
|
|
|
# inverse of the above transformation with power -1 and minvert()
|
|
sheet.set('A6', '=A4^-1 * minvert(A3) * A2^-1 * A5')
|
|
sheet.set('B6', '=minvert(B3) * B4^-1 * minvert(B2) * B5')
|
|
sheet.set('C6', '=C4^-1 * C2^-1 * C3^-1 * C5')
|
|
sheet.set('D6', '=minvert(D4*D2) * minvert(D3) * D5')
|
|
sheet.set('E6', '=(E2 * E3)^-1 * E4^-1 * E5')
|
|
sheet.set('F6', '=(F3*F4*F2)^-1 * F5')
|
|
|
|
self.doc.recompute()
|
|
|
|
self.assertEqual(sheet.A1,vec)
|
|
|
|
self.assertEqual(sheet.B1,mat)
|
|
self.assertEqual(sheet.C1,mat)
|
|
self.assertEqual(sheet.A2,mat)
|
|
|
|
self.assertEqual(sheet.B2,imat*imat)
|
|
self.assertEqual(sheet.B2,mat**-2)
|
|
self.assertEqual(sheet.C2,imat)
|
|
self.assertEqual(sheet.C2,mat**-1)
|
|
self.assertEqual(sheet.D2,FreeCAD.Matrix())
|
|
self.assertEqual(sheet.D2,mat**0)
|
|
self.assertEqual(sheet.E2,mat)
|
|
self.assertEqual(sheet.E2,mat**1)
|
|
self.assertEqual(sheet.F2,mat*mat)
|
|
self.assertEqual(sheet.F2,mat**2)
|
|
|
|
self.assertTrue(sheet.H2.startswith(u'ERR: Cannot invert singular matrix'))
|
|
|
|
self.assertEqual(sheet.A3,rot)
|
|
|
|
rtol = 1e-12
|
|
self.assertTrue(sheet.B3.isSame(irot*irot,rtol))
|
|
self.assertTrue(sheet.B3.isSame(rot**-2,rtol))
|
|
self.assertTrue(sheet.C3.isSame(irot,rtol))
|
|
self.assertTrue(sheet.C3.isSame(rot**-1,rtol))
|
|
self.assertTrue(sheet.D3.isSame(FreeCAD.Rotation(),rtol))
|
|
self.assertTrue(sheet.D3.isSame(rot**0,rtol))
|
|
self.assertTrue(sheet.E3.isSame(rot,rtol))
|
|
self.assertTrue(sheet.E3.isSame(rot**1,rtol))
|
|
self.assertTrue(sheet.F3.isSame(rot*rot,rtol))
|
|
self.assertTrue(sheet.F3.isSame(rot**2,rtol))
|
|
|
|
self.assertEqual(sheet.A4,pla)
|
|
|
|
self.assertTrue(plm_equal(sheet.B4,ipla*ipla))
|
|
self.assertTrue(plm_equal(sheet.B4,pla**-2))
|
|
self.assertTrue(plm_equal(sheet.C4,ipla))
|
|
self.assertTrue(plm_equal(sheet.C4,pla**-1))
|
|
self.assertTrue(plm_equal(sheet.D4,FreeCAD.Placement()))
|
|
self.assertTrue(plm_equal(sheet.D4,pla**0))
|
|
self.assertTrue(plm_equal(sheet.E4,pla))
|
|
self.assertTrue(plm_equal(sheet.E4,pla**1))
|
|
self.assertTrue(plm_equal(sheet.F4,pla*pla))
|
|
self.assertTrue(plm_equal(sheet.F4,pla**2))
|
|
|
|
tol = 1e-10
|
|
|
|
self.assertLess(sheet.A5.distanceToPoint(
|
|
sheet.A2.multiply(sheet.A3.Matrix).multiply(sheet.A4.Matrix).multVec(vec)),tol)
|
|
self.assertLess(sheet.B5.distanceToPoint(
|
|
sheet.B2.multiply(sheet.B4.Matrix).multiply(sheet.B3.Matrix).multVec(vec)),tol)
|
|
self.assertLess(sheet.C5.distanceToPoint(
|
|
sheet.C3.Matrix.multiply(sheet.C2).multiply(sheet.C4.Matrix).multVec(vec)),tol)
|
|
self.assertLess(sheet.D5.distanceToPoint(
|
|
sheet.D3.Matrix.multiply(sheet.D4.Matrix).multiply(sheet.D2).multVec(vec)),tol)
|
|
self.assertLess(sheet.E5.distanceToPoint(
|
|
sheet.E4.Matrix.multiply(sheet.E2).multiply(sheet.E3.Matrix).multVec(vec)),tol)
|
|
self.assertLess(sheet.F5.distanceToPoint(
|
|
sheet.F3.Matrix.multiply(sheet.F4.Matrix).multiply(sheet.F2).multVec(vec)),tol)
|
|
|
|
self.assertLess(sheet.A6.distanceToPoint(vec),tol)
|
|
self.assertLess(sheet.B6.distanceToPoint(vec),tol)
|
|
self.assertLess(sheet.C6.distanceToPoint(vec),tol)
|
|
self.assertLess(sheet.D6.distanceToPoint(vec),tol)
|
|
self.assertLess(sheet.E6.distanceToPoint(vec),tol)
|
|
self.assertLess(sheet.F6.distanceToPoint(vec),tol)
|
|
|
|
def testIssue3128(self):
|
|
""" Regression test for issue 3128; mod should work with arbitrary units for both arguments """
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '=mod(7mm;3mm)')
|
|
sheet.set('A2', '=mod(7kg;3mm)')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A1, Units.Quantity('1'))
|
|
self.assertEqual(sheet.A2, Units.Quantity('1 kg/mm'))
|
|
|
|
def testIssue3363(self):
|
|
""" Regression test for issue 3363; Nested conditionals statement fails with additional conditional statement in false-branch"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '1')
|
|
sheet.set('B1', '=A1==1?11:(A1==2?12:13)')
|
|
sheet.set('C1', '=A1==1?(A1==2?12:13) : 11')
|
|
self.doc.recompute()
|
|
|
|
# Save and close first document
|
|
self.doc.saveAs(self.TempPath + os.sep + 'conditionals.fcstd')
|
|
FreeCAD.closeDocument(self.doc.Name)
|
|
|
|
# Open documents again
|
|
self.doc = FreeCAD.openDocument(self.TempPath + os.sep + 'conditionals.fcstd')
|
|
|
|
sheet = self.doc.getObject('Spreadsheet')
|
|
self.assertEqual(sheet.getContents('B1'), '=A1 == 1 ? 11 : (A1 == 2 ? 12 : 13)')
|
|
self.assertEqual(sheet.getContents('C1'), '=A1 == 1 ? (A1 == 2 ? 12 : 13) : 11')
|
|
|
|
def testIssue3432(self):
|
|
""" Regression test for issue 3432; numbers with units are ignored from aggregates"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A1', '1mm')
|
|
sheet.set('B1', '2mm')
|
|
sheet.set('C1', '=max(A1:B1;3mm)')
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.get('C1'), Units.Quantity('3 mm'))
|
|
|
|
def testInsertRowsAlias(self):
|
|
""" Regression test for issue 4429; insert rows to sheet with aliases"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A3', '1')
|
|
sheet.setAlias('A3', 'alias1')
|
|
sheet.set('A4', '=alias1 + 1')
|
|
sheet.setAlias('A4', 'alias2')
|
|
sheet.set('A5', '=alias2 + 1')
|
|
self.doc.recompute()
|
|
sheet.insertRows('1', 1)
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A6, 3)
|
|
|
|
def testInsertColumnsAlias(self):
|
|
""" Regression test for issue 4429; insert columns to sheet with aliases"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('C1', '1')
|
|
sheet.setAlias('C1', 'alias1')
|
|
sheet.set('D1', '=alias1 + 1')
|
|
sheet.setAlias('D1', 'alias2')
|
|
sheet.set('E1', '=alias2 + 1')
|
|
self.doc.recompute()
|
|
sheet.insertColumns('A', 1)
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.F1, 3)
|
|
|
|
def testRemoveRowsAlias(self):
|
|
""" Regression test for issue 4429; remove rows from sheet with aliases"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('A3', '1')
|
|
sheet.setAlias('A3', 'alias1')
|
|
sheet.set('A5', '=alias1 + 1')
|
|
sheet.setAlias('A5', 'alias2')
|
|
sheet.set('A4', '=alias2 + 1')
|
|
self.doc.recompute()
|
|
sheet.removeRows('1', 1)
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.A3, 3)
|
|
|
|
def testRemoveColumnsAlias(self):
|
|
""" Regression test for issue 4429; remove columns from sheet with aliases"""
|
|
sheet = self.doc.addObject('Spreadsheet::Sheet','Spreadsheet')
|
|
sheet.set('C1', '1')
|
|
sheet.setAlias('C1', 'alias1')
|
|
sheet.set('E1', '=alias1 + 1')
|
|
sheet.setAlias('E1', 'alias2')
|
|
sheet.set('D1', '=alias2 + 1')
|
|
self.doc.recompute()
|
|
sheet.removeColumns('A', 1)
|
|
self.doc.recompute()
|
|
self.assertEqual(sheet.C1, 3)
|
|
|
|
def tearDown(self):
|
|
#closing doc
|
|
FreeCAD.closeDocument(self.doc.Name)
|