Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BigInt tests][No merge] ❌🐰 Apple #255

Open
wants to merge 2 commits into
base: biginteger
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
112 changes: 112 additions & 0 deletions Tests/BigIntTests/Apple/AppleBigIntDivTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//===--- AppleBigIntDivTests.swift ----------------------------*- swift -*-===//
//
// This source file is part of the Swift Numerics open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift Numerics project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import XCTest
@testable import BigIntModule

// swiftlint:disable line_length

private typealias TestCase = (x: String, y: String, quotient: String, remainder: String)

/// Additional tests for `div` operation
/// Based on: https://github.com/apple/swift/blob/master/test/Prototypes/BigInt.swift
class AppleBigIntDivTests: XCTestCase {

private let testCases: [TestCase] = [
("3GFWFN54YXNBS6K2ST8K9B89Q2AMRWCNYP4JAS5ZOPPZ1WU09MXXTIT27ZPVEG2Y",
"9Y1QXS4XYYDSBMU4N3LW7R3R1WKK",
"CIFJIVHV0K4MSX44QEX2US0MFFEAWJVQ8PJZ",
"26HILZ7GZQN8MB4O17NSPO5XN1JI"),
("7PM82EHP7ZN3ZL7KOPB7B8KYDD1R7EEOYWB6M4SEION47EMS6SMBEA0FNR6U9VAM70HPY4WKXBM8DCF1QOR1LE38NJAVOPOZEBLIU1M05",
"-202WEEIRRLRA9FULGA15RYROVW69ZPDHW0FMYSURBNWB93RNMSLRMIFUPDLP5YOO307XUNEFLU49FV12MI22MLCVZ5JH",
"-3UNIZHA6PAL30Y",
"1Y13W1HYB0QV2Z5RDV9Z7QXEGPLZ6SAA2906T3UKA46E6M4S6O9RMUF5ETYBR2QT15FJZP87JE0W06FA17RYOCZ3AYM3"),
("-ICT39SS0ONER9Z7EAPVXS3BNZDD6WJA791CV5LT8I4POLF6QYXBQGUQG0LVGPVLT0L5Z53BX6WVHWLCI5J9CHCROCKH3B381CCLZ4XAALLMD",
"6T1XIVCPIPXODRK8312KVMCDPBMC7J4K0RWB7PM2V4VMBMODQ8STMYSLIXFN9ORRXCTERWS5U4BLUNA4H6NG8O01IM510NJ5STE",
"-2P2RVZ11QF",
"-3YSI67CCOD8OI1HFF7VF5AWEQ34WK6B8AAFV95U7C04GBXN0R6W5GM5OGOO22HY0KADIUBXSY13435TW4VLHCKLM76VS51W5Z9J"),
("-326JY57SJVC",
"-8H98AQ1OY7CGAOOSG",
"0",
"-326JY57SJVC"),
("-XIYY0P3X9JIDF20ZQG2CN5D2Q5CD9WFDDXRLFZRDKZ8V4TSLE2EHRA31XL3YOHPYLE0I0ZAV2V9RF8AGPCYPVWEIYWWWZ3HVDR64M08VZTBL85PR66Z2F0W5AIDPXIAVLS9VVNLNA6I0PKM87YW4T98P0K",
"-BUBZEC4NTOSCO0XHCTETN4ROPSXIJBTEFYMZ7O4Q1REOZO2SFU62KM3L8D45Z2K4NN3EC4BSRNEE",
"2TX1KWYGAW9LAXUYRXZQENY5P3DSVXJJXK4Y9DWGNZHOWCL5QD5PLLZCE6D0G7VBNP9YGFC0Z9XIPCB",
"-3LNPZ9JK5PUXRZ2Y1EJ4E3QRMAMPKZNI90ZFOBQJM5GZUJ84VMF8EILRGCHZGXJX4AXZF0Z00YA"),
("AZZBGH7AH3S7TVRHDJPJ2DR81H4FY5VJW2JH7O4U7CH0GG2DSDDOSTD06S4UM0HP1HAQ68B2LKKWD73UU0FV5M0H0D0NSXUJI7C2HW3P51H1JM5BHGXK98NNNSHMUB0674VKJ57GVVGY4",
"1LYN8LRN3PY24V0YNHGCW47WUWPLKAE4685LP0J74NZYAIMIBZTAF71",
"6TXVE5E9DXTPTHLEAG7HGFTT0B3XIXVM8IGVRONGSSH1UC0HUASRTZX8TVM2VOK9N9NATPWG09G7MDL6CE9LBKN",
"WY37RSPBTEPQUA23AXB3B5AJRIUL76N3LXLP3KQWKFFSR7PR4E1JWH"),
("1000000000000000000000000000000000000000000000",
"1000000000000000000000000000000000000",
"1000000000",
"0")
]

func test_run() {
for testCaseStrings in self.testCases {
guard let values = self.parseTestCase(case: testCaseStrings) else {
continue
}

let x = values.x
let y = values.y
let result = x.quotientAndRemainder(dividingBy: y)

let msg = "\(testCaseStrings.x) / \(testCaseStrings.y)"
XCTAssertEqual(result.quotient, values.quotient, msg)
XCTAssertEqual(result.remainder, values.remainder, msg)

let mulResult = result.quotient * y + result.remainder
XCTAssertEqual(mulResult, x, msg)
}
}

private struct TestCaseValues {
fileprivate let x: BigInt
fileprivate let y: BigInt
fileprivate let quotient: BigInt
fileprivate let remainder: BigInt
}

private func parseTestCase(case c: TestCase,
file: StaticString = #file,
line: UInt = #line) -> TestCaseValues? {
let radix = 36

guard let x = BigInt(c.x, radix: radix) else {
XCTFail("Unable to parse x: \(c.x)", file: file, line: line)
return nil
}

guard let y = BigInt(c.y, radix: radix) else {
XCTFail("Unable to parse y: \(c.y)", file: file, line: line)
return nil
}

guard let quotient = BigInt(c.quotient, radix: radix) else {
XCTFail("Unable to parse quotient: \(c.quotient)", file: file, line: line)
return nil
}

guard let remainder = BigInt(c.remainder, radix: radix) else {
XCTFail("Unable to parse remainder: \(c.remainder)", file: file, line: line)
return nil
}

return TestCaseValues(
x: x,
y: y,
quotient: quotient,
remainder: remainder
)
}
}
276 changes: 276 additions & 0 deletions Tests/BigIntTests/Apple/AppleBigIntTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
//===--- AppleBigIntTests.swift -------------------------------*- swift -*-===//
//
// This source file is part of the Swift Numerics open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift Numerics project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import XCTest
@testable import BigIntModule

// Tests were partially copied from:
// https://github.com/apple/swift/blob/master/test/Prototypes/BigInt.swift

class AppleBigIntTests: XCTestCase {

// MARK: - Initialization

func test_initialization() {
let x = BigInt(1_000_000 as Int)
XCTAssertEqual(x, 1_000_000)

let y = BigInt(1_000 as UInt16)
XCTAssertEqual(y, 1_000)

let z = BigInt(-1_000_000 as Int)
XCTAssertEqual(z, -1_000_000)
XCTAssertTrue(z < 0)
}

// MARK: - Identity/Fixed point

func test_identity_fixedPoint() {
let x = BigInt(Int.max)
let y = -x

XCTAssertEqual(x / x, 1)
XCTAssertEqual(x / y, -1)
XCTAssertEqual(y / x, -1)
XCTAssertEqual(y / y, 1)
XCTAssertEqual(x % x, 0)
XCTAssertEqual(x % y, 0)
XCTAssertEqual(y % x, 0)
XCTAssertEqual(y % y, 0)

XCTAssertEqual(x * 1, x)
XCTAssertEqual(y * 1, y)
XCTAssertEqual(x * -1, y)
XCTAssertEqual(y * -1, x)
XCTAssertEqual(-x, y)
XCTAssertEqual(-y, x)

XCTAssertEqual(x + 0, x)
XCTAssertEqual(y + 0, y)
XCTAssertEqual(x - 0, x)
XCTAssertEqual(y - 0, y)

XCTAssertEqual(x - x, 0)
XCTAssertEqual(y - y, 0)
}

// MARK: - Zero arithmetic

func test_zeroArithmetic() {
let x: BigInt = 1
XCTAssertEqual(x - x, 0)

let y: BigInt = -1
XCTAssertEqual(y - y, 0)

XCTAssertEqual(x * 0, 0)
}

// MARK: - Conformances

func test_conformances() {
// Comparable
let x = BigInt(Int16.max)
let y = x * x * x
XCTAssertLessThan(y, y + 1)
XCTAssertGreaterThan(y, y - 1)
XCTAssertGreaterThan(y, 0)

let z = -y
XCTAssertLessThan(z, z + 1)
XCTAssertGreaterThan(z, z - 1)
XCTAssertLessThan(z, 0)

XCTAssertEqual(-z, y)
XCTAssertEqual(y + z, 0)

// Hashable
XCTAssertNotEqual(x.hashValue, y.hashValue)
XCTAssertNotEqual(y.hashValue, z.hashValue)

let set = Set([x, y, z])
XCTAssertTrue(set.contains(x))
XCTAssertTrue(set.contains(y))
XCTAssertTrue(set.contains(z))
XCTAssertFalse(set.contains(-x))
}

// MARK: - BinaryInteger interop

func test_binaryInteger_interop() {
let x: BigInt = 100
let xComp = UInt8(x)
XCTAssertTrue(x == xComp)
XCTAssertTrue(x < xComp + 1)
XCTAssertFalse(xComp + 1 < x)

let y: BigInt = -100
let yComp = Int8(y)
XCTAssertTrue(y == yComp)
XCTAssertTrue(y < yComp + 1)
XCTAssertFalse(yComp + 1 < y)

let zComp = Int.min + 1
let z = BigInt(zComp)
XCTAssertTrue(z == zComp)
XCTAssertTrue(zComp == z)
XCTAssertFalse(zComp + 1 < z)
XCTAssertTrue(z < zComp + 1)

let w = BigInt(UInt32.max)
let wComp = UInt(truncatingIfNeeded: w)
XCTAssertTrue(w == wComp)
XCTAssertTrue(wComp == w)
XCTAssertTrue(wComp - 1 < w)
XCTAssertFalse(w < wComp - 1)
}

// MARK: - Huge

func test_huge() {
let x = BigInt(1_000_000)
XCTAssertGreaterThan(x, x - 1)
let y = -x
XCTAssertGreaterThan(y, y - 1)
}

// MARK: - Strings

// cSpell:ignore wtkgm UNIZHA

func test_strings() {
guard let x = BigInt("-171usy24wtkgm", radix: 36) else {
XCTFail("Parse failed")
return
}

XCTAssertEqual(
String(x, radix: 2, uppercase: false),
"-100111010100011100000111111110111011001110110100101110011010110"
)
XCTAssertEqual(String(x, radix: 10, uppercase: false), "-5666517882467146966")
XCTAssertEqual(String(x, radix: 16, uppercase: false), "-4ea383fdd9da5cd6")
XCTAssertEqual(String(x, radix: 36, uppercase: false), "-171usy24wtkgm")

XCTAssertTrue(BigInt("12345") == 12_345)
XCTAssertTrue(BigInt("-12345") == -12_345)

XCTAssertNil(BigInt("-3UNIZHA6PAL30Y", radix: 10))
XCTAssertNil(BigInt("---"))
XCTAssertNil(BigInt(" 123"))
}

private func toString(_ value: BigInt, base: Int) -> String {
return String(value, radix: base, uppercase: false)
}

// MARK: - Bitshift

func test_bitshift() {
XCTAssertEqual(BigInt(255) << 1, 510)
XCTAssertTrue(BigInt(UInt32.max) << 16 == UInt(UInt32.max) << 16)

var (x, y) = (1 as BigInt, 1 as UInt64)
for i in 0..<63 { // don't test 64-bit shift, UInt64 << 64 == 0
XCTAssertTrue(x << i == y << i, "Iteration: \(i)")
}

x = BigInt(-1)
let z = -1 as Int
for i in 0..<64 {
XCTAssertTrue(x << i == z << i, "Iteration: \(i)")
}
}

// MARK: - Bitwise

func test_bitwise() {
let values = [
BigInt(Int.max - 2),
BigInt(255),
BigInt(256),
BigInt(UInt32.max)
]

for value in values {
for x in [value, -value] {
XCTAssertTrue((x | 0) == x)
XCTAssertTrue((x & 0) == 0)
XCTAssertTrue((x & ~0) == x)
XCTAssertTrue((x ^ 0) == x)
XCTAssertTrue((x ^ ~0) == ~x)
XCTAssertTrue(x == BigInt(Int(truncatingIfNeeded: x)))
XCTAssertTrue(~x == BigInt(~Int(truncatingIfNeeded: x)))
}
}
}

// ==============================
// ======== CUSTOM TESTS ========
// ==============================

// MARK: - Magnitude

func test_magnitude() {
let values: [Int64] = [.min, -1, 0, 1, .max]

for value in values {
let x = BigInt(value).magnitude
let y = BigInt(value.magnitude)
XCTAssertEqual(x, y, "Value: \(value)")
}
}

// MARK: - MinRequiredWidth

/*
// === NOT SUPPORTED by current implementation ===

func test_minRequiredWidth() {
XCTAssertEqual(BigInt(0).minRequiredWidth, 0)

for shift in 0..<63 {
// >>> int.bit_length(1 << 0) -> 1
// >>> int.bit_length(1 << 1) -> 2
// >>> int.bit_length(1 << 2) -> 3
// >>> int.bit_length(1 << 63) -> 64
let value = BigInt(1) << shift
XCTAssertEqual(value.minRequiredWidth, shift + 1)
}

for shift in 0..<63 {
// >>> int.bit_length(-1 << 0) -> 1
// >>> int.bit_length(-1 << 1) -> 2
// >>> int.bit_length(-1 << 2) -> 3
// >>> int.bit_length(-1 << 63) -> 64
let value = BigInt(-1) << shift
XCTAssertEqual(value.minRequiredWidth, shift + 1)
}
}

func minRequiredWidthHelper() {
for plus in 0...15 {
let value = -plus
let str = abs(value) < 10 ? " -\(abs(value))" : value.description
print(str, "|", terminator: "")

withUnsafeBytes(of: value) { bufferPtr in
for byte in bufferPtr {
let hex = String(byte, radix: 2, uppercase: false)
let hexPad = hex.padding(toLength: 8, withPad: "0", startingAt: 0)
print(hexPad + " ", terminator: "")
}
print()
}
}
}
*/
}