Skip to content
This repository has been archived by the owner on Sep 3, 2021. It is now read-only.

Commit

Permalink
fix: allow CIDs to be compared through deep equality
Browse files Browse the repository at this point in the history
The changes in #131 broke the tests of IPFS and probably quite a few
other modules.

This sort of thing used to work, now does not:

```js
expect(ipfs.bitswap.unwant.calledWith(new CID(cidStr), defaultOptions)).to.be.true()
```

The reason it breaks is because internally `calledWith` does a `deepEqual`
on the args which compares (among other things) the properties of the passed
objects.

We used to use `Object.defineProperty` to create cached versions of
expensive to calculate fields which makes fields non-enumerable by
default so they are skipped during the `deepEqual` check.

different fields depending on how which constructor branch was hit or
worse, if the instances properties have been accessed.
  • Loading branch information
achingbrain committed Dec 11, 2020
1 parent 26c436d commit 646c766
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"uint8arrays": "^1.1.0"
},
"devDependencies": {
"@sinonjs/samsam": "^5.3.0",
"aegir": "^29.0.1",
"multihashing-async": "^2.0.1"
},
Expand Down
9 changes: 6 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class CID {
this.multibaseName = 'base58btc'
}
CID.validateCID(this)
this.string = version
Object.defineProperty(this, 'string', { value: version })
return
}

Expand Down Expand Up @@ -164,6 +164,7 @@ class CID {
*
*/
get bytes () {
// @ts-ignore
let bytes = this._bytes

if (!bytes) {
Expand All @@ -179,7 +180,7 @@ class CID {
}

// Cache this Uint8Array so it doesn't have to be recreated
this._bytes = bytes
Object.defineProperty(this, '_bytes', { value: bytes })
}

return bytes
Expand Down Expand Up @@ -248,7 +249,9 @@ class CID {
* @returns {string}
*/
toBaseEncodedString (base = this.multibaseName) {
// @ts-ignore non enumerable cache property
if (this.string && this.string.length !== 0 && base === this.multibaseName) {
// @ts-ignore non enumerable cache property
return this.string
}
let str
Expand All @@ -264,7 +267,7 @@ class CID {
}
if (base === this.multibaseName) {
// cache the string value
this.string = str
Object.defineProperty(this, 'string', { value: str })
}
return str
}
Expand Down
44 changes: 44 additions & 0 deletions test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const multihashing = require('multihashing-async')
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
const CID = require('../src')
const { deepEqual } = require('@sinonjs/samsam')

describe('CID', () => {
let hash
Expand Down Expand Up @@ -448,4 +449,47 @@ describe('CID', () => {
expect(cid.toBaseEncodedString()).to.equal(base32String)
})
})

describe('equality', () => {
it('should be deeply equal', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should be deeply equal when constructed from another CID', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1)

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should be deeply equal when constructed from an Uint8Array', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)

expect(deepEqual(cid1, cid2)).to.be.true()
})

it('should still be deeply equal after turning one into a base encoded string', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)
const cid3 = new CID(cid1.multihash)

cid3.toBaseEncodedString()

expect(deepEqual(cid2, cid3)).to.be.true()
})

it('should still be deeply equal after turning one into bytes', () => {
const cid1 = new CID('QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n')
const cid2 = new CID(cid1.multihash)
const cid3 = new CID(cid1.multihash)

cid3.bytes // eslint-disable-line no-unused-expressions

expect(deepEqual(cid2, cid3)).to.be.true()
})
})
})

0 comments on commit 646c766

Please sign in to comment.